diff --git a/plugins/ui/DESIGN.md b/plugins/ui/DESIGN.md index cbdb538bb..a50bc1912 100644 --- a/plugins/ui/DESIGN.md +++ b/plugins/ui/DESIGN.md @@ -1045,11 +1045,11 @@ ui.section( ###### Parameters -| Parameter | Type | Description | -| ----------- | ------- | ----------------------------------------- | -| `*children` | `Item` | The options to render within the section. | +| Parameter | Type | Description | +| ----------- | ------------- | ----------------------------------------- | +| `*children` | `Item` | The options to render within the section. | | `title` | `str \| None` | The title of the section. | -| `**props` | `Any` | Any other Section prop | +| `**props` | `Any` | Any other Section prop | ##### ui.picker @@ -1189,6 +1189,7 @@ picker7 = ui.picker( ``` ###### ui.list_action_group + A group of action buttons that can be used to create a list of actions. This component should be used within the actions prop of a `ListView` component. @@ -1202,16 +1203,16 @@ def list_action_group( ``` ###### Parameters -| Parameter | Type | Description | -|-------------------------|------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------| -| `*children` | `ActionGroupItem` | The actions to render within the action group. | -| `on_action` | `Callable[[ActionKey, Key], None] \| None` | Handler that is called when an item is pressed. The first argument is the key of the action, the second argument is the key of the list_view item. | -| `on_selection_change` | `Callable[[Selection, Key], None] \| None` | Handler that is called when the selection changes. The first argument is the selection, the second argument is the key of the list_view item. | -| `**props` | `Any` | Any other [ActionGroup](https://react-spectrum.adobe.com/react-spectrum/ActionGroup.html) prop. | - +| Parameter | Type | Description | +| --------------------- | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| `*children` | `ActionGroupItem` | The actions to render within the action group. | +| `on_action` | `Callable[[ActionKey, Key], None] \| None` | Handler that is called when an item is pressed. The first argument is the key of the action, the second argument is the key of the list_view item. | +| `on_selection_change` | `Callable[[Selection, Key], None] \| None` | Handler that is called when the selection changes. The first argument is the selection, the second argument is the key of the list_view item. | +| `**props` | `Any` | Any other [ActionGroup](https://react-spectrum.adobe.com/react-spectrum/ActionGroup.html) prop. | ###### ui.list_action_menu + A group of action buttons that can be used to create a list of actions. This component should be used within the actions prop of a `ListView` component. @@ -1225,17 +1226,20 @@ def list_action_menu( ``` ###### Parameters -| Parameter | Type | Description | -|-------------------------|------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------| -| `*children` | `ActionMenuItem` | The options to render within the picker. | -| `on_action` | `Callable[[ActionKey, Key], None] \| None` | Handler that is called when an item is pressed. The first argument is the key of the action, the second argument is the key of the list_view item. | -| `on_open_change` | `Callable[[bool, Key], None] \| None` | The first argument is a boolean indicating if the menu is open, the second argument is the key of the list_view item. | -| `**props` | `Any` | Any other [ActionMenu](https://react-spectrum.adobe.com/react-spectrum/ActionMenu.html) prop. | + +| Parameter | Type | Description | +| ---------------- | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| `*children` | `ActionMenuItem` | The options to render within the picker. | +| `on_action` | `Callable[[ActionKey, Key], None] \| None` | Handler that is called when an item is pressed. The first argument is the key of the action, the second argument is the key of the list_view item. | +| `on_open_change` | `Callable[[bool, Key], None] \| None` | The first argument is a boolean indicating if the menu is open, the second argument is the key of the list_view item. | +| `**props` | `Any` | Any other [ActionMenu](https://react-spectrum.adobe.com/react-spectrum/ActionMenu.html) prop. | ###### ui.list_view -A list view that can be used to create a list of items. Children should be one of two types: -1. If children are of type `Item`, they are the list items. -2. If children are of type `Table`, the values in the table are the list items. There can only be one child, the `Table`. + +A list view that can be used to create a list of items. Children should be one of two types: + +1. If children are of type `Item`, they are the list items. +2. If children are of type `Table`, the values in the table are the list items. There can only be one child, the `Table`. ```py import deephaven.ui as ui @@ -1249,28 +1253,28 @@ ui.list_view( default_selected_keys: Selection | None = None, selected_keys: Selection | None = None, render_empty_state: Element | None = None, - on_selection_change: Callable[[Selection], None] | None = None, + on_selection_change: Callable[[Selection], None] | None = None, on_change: Callable[[Selection], None] | None = None, **props: Any ) -> ListViewElement ``` ###### Parameters -| Parameter | Type | Description | -|-------------------------|------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `*children` | `Item \| Table` | The options to render within the list_view. | -| `key_column` | `ColumnName \| None` | Only valid if children are of type `Table`. The column of values to use as item keys. Defaults to the first column. | -| `label_column` | `ColumnName \| None` | Only valid if children are of type `Table`. The column of values to display as primary text. Defaults to the `key_column` value. | -| `description_column` | `ColumnName \| None` | Only valid if children are of type `Table`. The column of values to display as descriptions. | -| `icon_column` | `ColumnName \| None` | Only valid if children are of type `Table`. The column of values to map to icons. | -| `actions` | `ListActionGroupElement \| ListActionMenuElement \| None` | Only valid if children are of type Table. The action group or menus to render for all elements within the list view. | -| `default_selected_keys` | `Selection \| None` | The initial selected keys in the collection (uncontrolled). | -| `selected_keys` | `Selection \| None` | The currently selected keys in the collection (controlled). | -| `render_empty_state` | `Element \| None` | Sets what the `list_view` should render when there is no content to display. | -| `on_selection_change` | `Callable[[Selection], None] \| None` | Handler that is called when the selections changes. | -| `on_change` | `Callable[[Selection], None] \| None` | Alias of `on_selection_change`. Handler that is called when the selections changes. | -| `**props` | `Any` | Any other [ListView](https://react-spectrum.adobe.com/react-spectrum/ListView.html) prop, with the exception of `items`, `dragAndDropHooks`, and `onLoadMore`. | +| Parameter | Type | Description | +| ----------------------- | --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `*children` | `Item \| Table` | The options to render within the list_view. | +| `key_column` | `ColumnName \| None` | Only valid if children are of type `Table`. The column of values to use as item keys. Defaults to the first column. | +| `label_column` | `ColumnName \| None` | Only valid if children are of type `Table`. The column of values to display as primary text. Defaults to the `key_column` value. | +| `description_column` | `ColumnName \| None` | Only valid if children are of type `Table`. The column of values to display as descriptions. | +| `icon_column` | `ColumnName \| None` | Only valid if children are of type `Table`. The column of values to map to icons. | +| `actions` | `ListActionGroupElement \| ListActionMenuElement \| None` | Only valid if children are of type Table. The action group or menus to render for all elements within the list view. | +| `default_selected_keys` | `Selection \| None` | The initial selected keys in the collection (uncontrolled). | +| `selected_keys` | `Selection \| None` | The currently selected keys in the collection (controlled). | +| `render_empty_state` | `Element \| None` | Sets what the `list_view` should render when there is no content to display. | +| `on_selection_change` | `Callable[[Selection], None] \| None` | Handler that is called when the selections changes. | +| `on_change` | `Callable[[Selection], None] \| None` | Alias of `on_selection_change`. Handler that is called when the selections changes. | +| `**props` | `Any` | Any other [ListView](https://react-spectrum.adobe.com/react-spectrum/ListView.html) prop, with the exception of `items`, `dragAndDropHooks`, and `onLoadMore`. | ```py import deephaven.ui as ui @@ -1355,19 +1359,22 @@ list_view7 = ui.list_view( ``` ###### ui.date_picker -A date picker that can be used to select a date. + +A date picker that can be used to select a date. There are three types that can be passed in to the props that control the date format: + 1. `LocalDate`: A LocalDate is a date without a time zone in the ISO-8601 system, such as "2007-12-03" or "2057-01-28". -This will create a date picker with a granularity of days. + This will create a date picker with a granularity of days. 2. `Instant`: An Instant represents an unambiguous specific point on the timeline, such as 2021-04-12T14:13:07 UTC. -This will create a date picker with a granularity of seconds in UTC. + This will create a date picker with a granularity of seconds in UTC. 3. `ZonedDateTime`: A ZonedDateTime represents an unambiguous specific point on the timeline with an associated time zone, such as 2021-04-12T14:13:07 America/New_York. -This will create a date picker with a granularity of seconds in the specified time zone. + This will create a date picker with a granularity of seconds in the specified time zone. -The format of the date picker and the type of the value passed to the `on_change` handler +The format of the date picker and the type of the value passed to the `on_change` handler is determined by the type of the following props in order of precedence: -1. `value` + +1. `value` 2. `default_value` 3. `placeholder_value` @@ -1389,8 +1396,9 @@ ui.date_picker( ``` ###### Parameters + | Parameter | Type | Description | -|----------------------|----------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| -------------------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `placeholder_value` | `Date \| None` | A placeholder date that influences the format of the placeholder shown when no value is selected. Defaults to today at midnight in the user's timezone. | | `value` | `Date \| None` | The current value (controlled). | | `default_value` | `Date \| None` | The default value (uncontrolled). | @@ -1516,7 +1524,7 @@ ui.combo_box( ###### Parameters | Parameter | Type | Description | -| ---------------------- | ----------------------------------------------------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ---------------------- | ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `*children` | `Item \| SectionElement \| Table \| PartitionedTable` | The options to render within the combo_box. | | `key_column` | `ColumnName \| None` | Only valid if children are of type `Table` or `PartitionedTable`. The column of values to use as item keys. Defaults to the first column. | | `label_column` | `ColumnName \| None` | Only valid if children are of type `Table` or `PartitionedTable`. The column of values to display as primary text. Defaults to the `key_column` value. | @@ -1530,7 +1538,7 @@ ui.combo_box( | `on_input_change` | `Callable[[str], None] \| None` | Handler that is called when the search input value changes. | | `on_selection_change` | `Callable[[Key], None] \| None` | Handler that is called when the selection changes. | | `on_change` | `Callable[[Key], None] \| None` | Alias of `on_selection_change`. Handler that is called when the selection changes. | -| `on_open_change` | `Callable[[bool, MenuTriggerAction], None] \| None` | Method that is called when the open state of the menu changes. Returns the new open state and the action that caused the opening of the menu. | +| `on_open_change` | `Callable[[bool, MenuTriggerAction], None] \| None` | Method that is called when the open state of the menu changes. Returns the new open state and the action that caused the opening of the menu. | | `**props` | `Any` | Any other [Combo_Box](https://react-spectrum.adobe.com/react-spectrum/ComboBox.html) prop, with the exception of `items`, `validate`, `errorMessage` (as a callback) and `onLoadMore` | ```py @@ -2186,7 +2194,7 @@ ListViewItem = Stringable | ItemElement LocalDateConvertible = Union[None, LocalDate, str, datetime.date, datetime.datetime, numpy.datetime64, pandas.Timestamp] InstantConvertible = Union[None, Instant, int, str, datetime.datetime, numpy.datetime64, pandas.Timestamp] ZonedDateTimeConvertible = Union[None, ZonedDateTime, str, datetime.datetime, numpy.datetime64, pandas.Timestamp] -Date = Instant | LocalDate | ZonedDateTime | LocalDateConvertible | InstantConvertible | ZonedDateTimeConvertible +Date = Instant | LocalDate | ZonedDateTime | LocalDateConvertible | InstantConvertible | ZonedDateTimeConvertible Granularity = Literal["DAY", "HOUR", "MINUTE", "SECOND"] MenuTriggerAction = Literal["FOCUS", "INPUT", "MANUAL"] @@ -2358,7 +2366,7 @@ tft = double_text_filter_table(_stocks) Which should result in a UI like this: -![Double Text Filter Tables](examples/assets/double-tft.png) +![Double Text Filter Tables](docs/_assets/double-tft.png) How does that look when the notebook is executed? When does each code block execute? diff --git a/plugins/ui/README.md b/plugins/ui/README.md index 7dd21cfdc..25bc1f55c 100644 --- a/plugins/ui/README.md +++ b/plugins/ui/README.md @@ -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 diff --git a/plugins/ui/docs/Plotting.md b/plugins/ui/docs/Plotting.md new file mode 100644 index 000000000..23c219fac --- /dev/null +++ b/plugins/ui/docs/Plotting.md @@ -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") +``` diff --git a/plugins/ui/examples/README.md b/plugins/ui/docs/README.md similarity index 96% rename from plugins/ui/examples/README.md rename to plugins/ui/docs/README.md index e1e4002b7..a385611b8 100644 --- a/plugins/ui/examples/README.md +++ b/plugins/ui/docs/README.md @@ -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 @@ -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`. @@ -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 @@ -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 @@ -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. @@ -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 @@ -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) @@ -201,7 +201,7 @@ def ui_checkbox(): my_checkbox = ui_checkbox() ``` -![Checkbox](assets/checkbox.png) +![Checkbox](_assets/checkbox.png) ## Picker (string values) @@ -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) @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -513,7 +513,7 @@ my_dash = ui.dashboard( ) ``` -![Stock Dashboard](assets/my_dash.png) +![Stock Dashboard](_assets/my_dash.png) ## Custom Components Dashboard @@ -611,7 +611,7 @@ def multiwave(): mw = ui.dashboard(multiwave()) ``` -![Multiwave Dashboard](assets/multiwave_dashboard.png) +![Multiwave Dashboard](_assets/multiwave_dashboard.png) # Other Examples @@ -666,7 +666,7 @@ def waves(): w = waves() ``` -![Waves](assets/waves.png) +![Waves](_assets/waves.png) ## Custom hook @@ -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: @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/plugins/ui/examples/assets/button_events.png b/plugins/ui/docs/_assets/button_events.png similarity index 100% rename from plugins/ui/examples/assets/button_events.png rename to plugins/ui/docs/_assets/button_events.png diff --git a/plugins/ui/examples/assets/change_monitor.png b/plugins/ui/docs/_assets/change_monitor.png similarity index 100% rename from plugins/ui/examples/assets/change_monitor.png rename to plugins/ui/docs/_assets/change_monitor.png diff --git a/plugins/ui/examples/assets/checkbox.png b/plugins/ui/docs/_assets/checkbox.png similarity index 100% rename from plugins/ui/examples/assets/checkbox.png rename to plugins/ui/docs/_assets/checkbox.png diff --git a/plugins/ui/examples/assets/counter.png b/plugins/ui/docs/_assets/counter.png similarity index 100% rename from plugins/ui/examples/assets/counter.png rename to plugins/ui/docs/_assets/counter.png diff --git a/plugins/ui/examples/assets/docker.png b/plugins/ui/docs/_assets/docker.png similarity index 100% rename from plugins/ui/examples/assets/docker.png rename to plugins/ui/docs/_assets/docker.png diff --git a/plugins/ui/examples/assets/double-tft.png b/plugins/ui/docs/_assets/double-tft.png similarity index 100% rename from plugins/ui/examples/assets/double-tft.png rename to plugins/ui/docs/_assets/double-tft.png diff --git a/plugins/ui/examples/assets/double_table.png b/plugins/ui/docs/_assets/double_table.png similarity index 100% rename from plugins/ui/examples/assets/double_table.png rename to plugins/ui/docs/_assets/double_table.png diff --git a/plugins/ui/examples/assets/foo_bar.png b/plugins/ui/docs/_assets/foo_bar.png similarity index 100% rename from plugins/ui/examples/assets/foo_bar.png rename to plugins/ui/docs/_assets/foo_bar.png diff --git a/plugins/ui/examples/assets/form.png b/plugins/ui/docs/_assets/form.png similarity index 100% rename from plugins/ui/examples/assets/form.png rename to plugins/ui/docs/_assets/form.png diff --git a/plugins/ui/examples/assets/form_submit.png b/plugins/ui/docs/_assets/form_submit.png similarity index 100% rename from plugins/ui/examples/assets/form_submit.png rename to plugins/ui/docs/_assets/form_submit.png diff --git a/plugins/ui/examples/assets/handling_events.png b/plugins/ui/docs/_assets/handling_events.png similarity index 100% rename from plugins/ui/examples/assets/handling_events.png rename to plugins/ui/docs/_assets/handling_events.png diff --git a/plugins/ui/examples/assets/hello_world.png b/plugins/ui/docs/_assets/hello_world.png similarity index 100% rename from plugins/ui/examples/assets/hello_world.png rename to plugins/ui/docs/_assets/hello_world.png diff --git a/plugins/ui/examples/assets/multiwave_dashboard.png b/plugins/ui/docs/_assets/multiwave_dashboard.png similarity index 100% rename from plugins/ui/examples/assets/multiwave_dashboard.png rename to plugins/ui/docs/_assets/multiwave_dashboard.png diff --git a/plugins/ui/examples/assets/my_dash.png b/plugins/ui/docs/_assets/my_dash.png similarity index 100% rename from plugins/ui/examples/assets/my_dash.png rename to plugins/ui/docs/_assets/my_dash.png diff --git a/plugins/ui/examples/assets/picker.png b/plugins/ui/docs/_assets/picker.png similarity index 100% rename from plugins/ui/examples/assets/picker.png rename to plugins/ui/docs/_assets/picker.png diff --git a/plugins/ui/examples/assets/range_table.png b/plugins/ui/docs/_assets/range_table.png similarity index 100% rename from plugins/ui/examples/assets/range_table.png rename to plugins/ui/docs/_assets/range_table.png diff --git a/plugins/ui/examples/assets/shared_state.png b/plugins/ui/docs/_assets/shared_state.png similarity index 100% rename from plugins/ui/examples/assets/shared_state.png rename to plugins/ui/docs/_assets/shared_state.png diff --git a/plugins/ui/examples/assets/stock_rollup.png b/plugins/ui/docs/_assets/stock_rollup.png similarity index 100% rename from plugins/ui/examples/assets/stock_rollup.png rename to plugins/ui/docs/_assets/stock_rollup.png diff --git a/plugins/ui/examples/assets/stock_widget_plot.png b/plugins/ui/docs/_assets/stock_widget_plot.png similarity index 100% rename from plugins/ui/examples/assets/stock_widget_plot.png rename to plugins/ui/docs/_assets/stock_widget_plot.png diff --git a/plugins/ui/examples/assets/stock_widget_table_invalid.png b/plugins/ui/docs/_assets/stock_widget_table_invalid.png similarity index 100% rename from plugins/ui/examples/assets/stock_widget_table_invalid.png rename to plugins/ui/docs/_assets/stock_widget_table_invalid.png diff --git a/plugins/ui/examples/assets/stock_widget_table_valid.png b/plugins/ui/docs/_assets/stock_widget_table_valid.png similarity index 100% rename from plugins/ui/examples/assets/stock_widget_table_valid.png rename to plugins/ui/docs/_assets/stock_widget_table_valid.png diff --git a/plugins/ui/examples/assets/table_events.png b/plugins/ui/docs/_assets/table_events.png similarity index 100% rename from plugins/ui/examples/assets/table_events.png rename to plugins/ui/docs/_assets/table_events.png diff --git a/plugins/ui/examples/assets/table_hooks.png b/plugins/ui/docs/_assets/table_hooks.png similarity index 100% rename from plugins/ui/examples/assets/table_hooks.png rename to plugins/ui/docs/_assets/table_hooks.png diff --git a/plugins/ui/examples/assets/text_field.png b/plugins/ui/docs/_assets/text_field.png similarity index 100% rename from plugins/ui/examples/assets/text_field.png rename to plugins/ui/docs/_assets/text_field.png diff --git a/plugins/ui/examples/assets/text_filter_table.png b/plugins/ui/docs/_assets/text_filter_table.png similarity index 100% rename from plugins/ui/examples/assets/text_filter_table.png rename to plugins/ui/docs/_assets/text_filter_table.png diff --git a/plugins/ui/examples/assets/wave_input.png b/plugins/ui/docs/_assets/wave_input.png similarity index 100% rename from plugins/ui/examples/assets/wave_input.png rename to plugins/ui/docs/_assets/wave_input.png diff --git a/plugins/ui/examples/assets/waves.png b/plugins/ui/docs/_assets/waves.png similarity index 100% rename from plugins/ui/examples/assets/waves.png rename to plugins/ui/docs/_assets/waves.png diff --git a/plugins/ui/examples/assets/waves_with_plot.png b/plugins/ui/docs/_assets/waves_with_plot.png similarity index 100% rename from plugins/ui/examples/assets/waves_with_plot.png rename to plugins/ui/docs/_assets/waves_with_plot.png