Skip to content

Commit

Permalink
docs: start plotting docs including one-click behaviour
Browse files Browse the repository at this point in the history
- Reename examples as docs
- Create a dh.ui plotting doc
- Rename assets as _assets for folder sort order
- Change links from assets to _assets
- Prettier changes on md files touched
  • Loading branch information
dsmmcken committed Apr 24, 2024
1 parent c108f44 commit bc87f4e
Show file tree
Hide file tree
Showing 32 changed files with 180 additions and 72 deletions.
100 changes: 54 additions & 46 deletions plugins/ui/DESIGN.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion plugins/ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ tox -e py

## Usage

Once you have the JS and python plugins installed and the server started, you can use deephaven.ui. See [examples](examples/README.md) for examples.
Once you have the JS and python plugins installed and the server started, you can use deephaven.ui. See [examples](docs/README.md) for examples.

## Logging

Expand Down
100 changes: 100 additions & 0 deletions plugins/ui/docs/Plotting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
title: Plotting and dh.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.

## 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.

```python
import deephaven.plot.express as dx
import deephaven.ui as ui

_stocks = dx.data.stocks()

@ui.component
def plot_filtered_table(table, inital_value):
text, set_text = ui.use_state("DOG")
# the filter is memoized so that it is only recalculated when the text changes
filtered_table = ui.use_memo(
lambda: table.where(f"sym = `{text.upper()}`"), [table, text]
)
return [
ui.text_field(value=text, on_change=set_text),
dx.line(filtered_table, x="timestamp", y="price", title=f"Filtered by: {text}"),
]


p = plot_filtered_table(_stocks, "DOG")
```

## Plotting a paritioned table

Using a partitioned table, as opposed to a where, can be more efficient if you are going to be filtering the same table multiple times with different values. This is because the partitioning is only done once, and then the key is selected from the partitioned table. Compared to using a where statement, it can be faster to return results, but at the expense of the query engine using more memory. Depending on the size of your table and the number of unique values in the partition key, this can be a tradeoff worth making or not.

```python
import deephaven.plot.express as dx
import deephaven.ui as ui

_stocks = dx.data.stocks()

@ui.component
def plot_paritioned_table(table, inital_value):
text, set_text = ui.use_state(inital_value)
# memoize the parition by so that it only performed once
paritioned_table = ui.use_memo(lambda: table.partition_by(["sym"]), [table])
constituent_table = ui.use_memo(
lambda: paritioned_table.get_constituent(text.upper()), [paritioned_table, text]
)
return [
ui.text_field(value=text, on_change=set_text),
# only attempt to plot valid parition keys
dx.line(
constituent_table, x="timestamp", y="price", title=f"Parition key: {text}"
)
if constituent_table != None
else ui.text("Please enter a valid parition."),
]


p = plot_paritioned_table(_stocks, "DOG")
```

## Combining a fitler and a parition by

Deephaven express allows you to plot by a partition and assign unique colors to each key. Sometimes as a user you may also want to filter the data in addition to partitioning it. We've previously referred to this as a "one-click plot by" behaviour in enterprise. This can be done by either filtering the table first and then partitioning it, or partitioning it first and then filtering it. The choice of which to use depends on the size of the table and the number of unique values in the partition key. The first example is more like a traditional "one-click" component, and the second is more like a parameterized query. Both will give you the same result, but the first one may return results faster, whereas the second one may be more memory efficient.

```python
import deephaven.plot.express as dx
import deephaven.ui as ui

_stocks = dx.data.stocks()

# component using a parition_by[a,b] once, then filter on a
@ui.component
def parition_then_filter(table, by, inital_value):
text, set_text = ui.use_state(inital_value)
paritioned_table = ui.use_memo(lambda: table.partition_by(by),[table, by])
filtered = ui.use_memo(lambda: paritioned_table.filter(f"{by[0]} = `{text.upper()}`"), [text, paritioned_table])
return [
ui.text_field(value=text, on_change=set_text),
dx.line(filtered, x="timestamp", y="price", by=[f"{by[1]}"])
]

# component using a where on a, then re-paritions on b
@ui.component
def where_then_parition(table, by, inital_value):
text, set_text = ui.use_state(inital_value)
filtered = ui.use_memo(lambda: table.where(f"{by[0]} = `{text.upper()}`"),[text, table])
return [
ui.text_field(value=text, on_change=set_text),
dx.line(filtered, x="timestamp", y="price", by=[f"{by[1]}"])
]


# outputs the same thing, done two different ways depending on how you want the work done
ptf = parition_then_filter(_stocks,["sym", "exchange"], "DOG")
wtp = where_then_parition(_stocks,["sym", "exchange"], "DOG")
```
50 changes: 25 additions & 25 deletions plugins/ui/examples/README.md → plugins/ui/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ docker run --rm --name deephaven-ui -p 10000:10000 --pull=always ghcr.io/deephav
```

You'll need to find the link to open the UI in the Docker logs:
![docker](assets/docker.png)
![docker](_assets/docker.png)

# Using components

Expand All @@ -27,7 +27,7 @@ The `ui` package contains many _components_, which you can display in the UI:
hello_world = ui.heading("Hello World!")
```

![Basic Hello World example.](assets/hello_world.png)
![Basic Hello World example.](_assets/hello_world.png)

By assigning the component to the `hello_world` variable, it displays in the UI in a panel named `hello_world`.

Expand All @@ -39,7 +39,7 @@ Write functions to handle events. To write a button that will print event detail
my_button = ui.button("Click Me!", on_press=lambda e: print(f"Button was clicked! {e}"))
```

![Whenever the button is pressed, event details are printed to the console.](assets/handling_events.png)
![Whenever the button is pressed, event details are printed to the console.](_assets/handling_events.png)

## Creating components

Expand All @@ -59,7 +59,7 @@ def ui_foo_bar():
foo_bar = ui_foo_bar()
```

![Custom component being displayed.](assets/foo_bar.png)
![Custom component being displayed.](_assets/foo_bar.png)

## Using state

Expand Down Expand Up @@ -98,7 +98,7 @@ c1 = ui_counter()
c2 = ui_counter()
```

![Each counter has its own state.](assets/counter.png)
![Each counter has its own state.](_assets/counter.png)

> [!NOTE]
> Functions are prefixed with `use_` are called _hooks_. `use_state` is built-in to deephaven.ui, and there are other hooks built-in shown below. You can also create your own hooks.
Expand Down Expand Up @@ -160,7 +160,7 @@ def ui_shared_state():
shared_state = ui_shared_state()
```

![Buttons will always be in sync with shared state.](assets/shared_state.png)
![Buttons will always be in sync with shared state.](_assets/shared_state.png)

# Examples

Expand All @@ -181,7 +181,7 @@ def ui_input():
my_input = ui_input()
```

![Text field.](assets/text_field.png)
![Text field.](_assets/text_field.png)

## Checkbox (boolean)

Expand All @@ -201,7 +201,7 @@ def ui_checkbox():
my_checkbox = ui_checkbox()
```

![Checkbox](assets/checkbox.png)
![Checkbox](_assets/checkbox.png)

## Picker (string values)

Expand Down Expand Up @@ -238,7 +238,7 @@ def ui_picker():
my_picker = ui_picker()
```

![Use a picker to select from a list of items](assets/picker.png)
![Use a picker to select from a list of items](_assets/picker.png)

## Form (two variables)

Expand All @@ -261,7 +261,7 @@ def ui_form():
my_form = ui_form()
```

![Form with multiple inputs.](assets/form.png)
![Form with multiple inputs.](_assets/form.png)

## Form with submit

Expand All @@ -284,7 +284,7 @@ def ui_form_submit():
my_form_submit = ui_form_submit()
```

![Submitting a form and printing out the data.](assets/form_submit.png)
![Submitting a form and printing out the data.](_assets/form_submit.png)

## Button events

Expand Down Expand Up @@ -320,7 +320,7 @@ def ui_button_events():
my_button_events = ui_button_events()
```

![Print the details of all events when pressing a button.](assets/button_events.png)
![Print the details of all events when pressing a button.](_assets/button_events.png)

# Data Examples

Expand Down Expand Up @@ -352,7 +352,7 @@ def ui_text_filter_table(source, column):
my_text_filter_table = ui_text_filter_table(stocks, "sym")
```

![Table with a text field for filtering.](assets/text_filter_table.png)
![Table with a text field for filtering.](_assets/text_filter_table.png)

## Table with range filter

Expand Down Expand Up @@ -415,9 +415,9 @@ def ui_stock_widget_table(source, default_sym="", default_exchange=""):
my_stock_widget_table = ui_stock_widget_table(stocks, "", "")
```

![Stock Widget Table Invalid Input](assets/stock_widget_table_invalid.png)
![Stock Widget Table Invalid Input](_assets/stock_widget_table_invalid.png)

![Stock Widget Table Valid Input](assets/stock_widget_table_valid.png)
![Stock Widget Table Valid Input](_assets/stock_widget_table_valid.png)

## Plot with filters

Expand Down Expand Up @@ -451,7 +451,7 @@ def ui_stock_widget_plot(source, default_sym="", default_exchange=""):
my_stock_widget_plot = ui_stock_widget_plot(stocks, "CAT", "TPET")
```

![Stock Widget Plot](assets/stock_widget_plot.png)
![Stock Widget Plot](_assets/stock_widget_plot.png)

# Dashboard Examples

Expand Down Expand Up @@ -513,7 +513,7 @@ my_dash = ui.dashboard(
)
```

![Stock Dashboard](assets/my_dash.png)
![Stock Dashboard](_assets/my_dash.png)

## Custom Components Dashboard

Expand Down Expand Up @@ -611,7 +611,7 @@ def multiwave():
mw = ui.dashboard(multiwave())
```

![Multiwave Dashboard](assets/multiwave_dashboard.png)
![Multiwave Dashboard](_assets/multiwave_dashboard.png)

# Other Examples

Expand Down Expand Up @@ -666,7 +666,7 @@ def waves():
w = waves()
```

![Waves](assets/waves.png)
![Waves](_assets/waves.png)

## Custom hook

Expand Down Expand Up @@ -730,7 +730,7 @@ def waves():
w = waves()
```

![Wave Input](assets/wave_input.png)
![Wave Input](_assets/wave_input.png)

We can then re-use that hook to make a component that displays a plot as well:

Expand Down Expand Up @@ -762,7 +762,7 @@ def waves_with_plot():
wp = waves_with_plot()
```

![Waves with plot](assets/waves_with_plot.png)
![Waves with plot](_assets/waves_with_plot.png)

## Using Panels

Expand Down Expand Up @@ -910,7 +910,7 @@ def double_table(source):
dt = double_table(stocks)
```

![Double Table](assets/double_table.png)
![Double Table](_assets/double_table.png)

## Stock rollup

Expand Down Expand Up @@ -994,7 +994,7 @@ def stock_table(source):
st = stock_table(stocks)
```

![Stock Rollup](assets/stock_rollup.png)
![Stock Rollup](_assets/stock_rollup.png)

## Listening to Table Updates

Expand Down Expand Up @@ -1092,7 +1092,7 @@ Without the `use_liveness_scope` wrapping the lamdba, the newly created live tab

For more information on liveness scopes and why they are needed, see the [liveness scope documentation](https://deephaven.io/core/docs/conceptual/liveness-scope-concept/).

![Change Monitor](assets/change_monitor.png)
![Change Monitor](_assets/change_monitor.png)

## Tabs

Expand Down Expand Up @@ -1194,7 +1194,7 @@ def watch_lizards(source: Table):
watch = watch_lizards(stocks)
```

![Table Hooks](assets/table_hooks.png)
![Table Hooks](_assets/table_hooks.png)

## Multi-threading

Expand Down
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes

0 comments on commit bc87f4e

Please sign in to comment.