Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: dashboard #814

Merged
merged 17 commits into from
Oct 28, 2024
254 changes: 254 additions & 0 deletions plugins/ui/docs/components/dashboard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
# Dashboard

Dashboards allow you to layout a collection of ui components as panels as individuals pages.
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved

ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved
## Rules

1. Dashboards must be a child of the root script and not nested inside a `@ui.component`. Otherwise the application is unable to correctly determine the type of the component
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved
2. Dashboards must have one and only one child, typically a row or column.
3. Height and width of panels are summed to 100%
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved

## Key Components

There are 4 main children that make up dashboard: row, column, stack, dashboard.
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved

- **Row**: A container used to group elements horizontally. Each element is placed to the right of the previous one.
- **Column**: A container used to group elements vertically. Each element is placed below the previous one.
- **Stack**: A container used to group elements into tabs. Each element gets its own tab, with only one element visible at a time.
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved
- **Panel**: A container used to group elements
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved

## Layout Hierarchy

### Top-Level

Rows and columns are the "top" the layout tree. Columns should go inside rows and rows should go inside columns
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved

Note: nesting rows within rows or columns within columns is allowed but it may result in layouts being more complicated than necessary. Consider using stacks or panels instead.
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved

### Bottom-Level

Stacks and panels are considered the "bottom" of the layout tree. Once added, the layout in that section is considered complete.
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved

## Automatic Wrapping

Children are implicitly wrapped when necessary so the entire layout does not need to be explicitly defined.
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved

The rules for how it is applied:
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved

1. Dashboard - wrap in row/column if no single node is the default (e.g `[col, col]` as the child to dashboard would become `row(col, col)`)
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved
2. Row/Column
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved
- if there are children that are rows/columns, wrap the non-wrapped children with the same element (e.g `row(col(t1), t2)` becomes `row(col(t1), col(t2))`)
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved
- if none of the children are wrapped by rows/columns, they are wrapped in stacks (e.g `row(col(t1), col(t2))` from above becomes `row(col(stack(t1)), col(stack(t2)))`)
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved
3. Stacks - wrap non-panel children in panels (e.g `row(col(stack(t1)), col(stack(t2)))` becomes `row(col(stack(panel(t1))), col(stack(panel(t2))))`)
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved

End to end example: `dashboard([t1, t2])` would become `dashboard(column(stack(panel(t1)), stack(panel(t2))))`
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved

## Layout Examples
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved

### Row split (2x1)

```python
from deephaven import ui

my_dash = ui.dashboard(ui.row(ui.panel("A"), ui.panel("B")))
```

### Column split (1x2)

```python
from deephaven import ui

my_dash = ui.dashboard(ui.column(ui.panel("A"), ui.panel("B")))
```

### 2x2

```python
from deephaven import ui

my_dash = ui.dashboard(
ui.row(
ui.column(ui.panel("A"), ui.panel("C")), ui.column(ui.panel("B"), ui.panel("D"))
)
)
```

### 3x1

```python
from deephaven import ui

my_dash = ui.dashboard(ui.row(ui.panel("A"), ui.panel("B"), ui.panel("C")))
```

### Basic stack

```python
from deephaven import ui

my_dash = ui.dashboard(ui.stack(ui.panel("A"), ui.panel("B"), ui.panel("C")))
```

### Stack in a layout

```python
from deephaven import ui

my_dash = ui.dashboard(
ui.row(
ui.stack(ui.panel("A"), ui.panel("B"), ui.panel("C")),
ui.panel("D"),
ui.panel("E"),
)
)
```

### Varying widths

```python
from deephaven import ui

my_dash = ui.dashboard(ui.row(ui.stack(ui.panel("A"), width=70), ui.panel("B")))
```

### Varying height

```python
from deephaven import ui

my_dash = ui.dashboard(ui.column(ui.stack(ui.panel("A"), height=70), ui.panel("B")))
```

### Holy Grail

```python
from deephaven import ui

my_dash = ui.dashboard(
ui.column(
ui.panel("Header"),
ui.row(
ui.panel("Left Sidebar"),
ui.stack(ui.panel("Main Content"), width=70),
ui.panel("Right Sidebar"),
),
ui.panel("Footer"),
)
)
```

## Stateful Example

### Simple

ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved
```python
from deephaven import ui


@ui.component
def layout():
message, set_message = ui.use_state("Hello! How are you doing today?")
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved

return ui.row(
ui.panel(ui.text_field(value=message, on_change=set_message, width="100%")),
ui.panel(message),
)


my_dash = ui.dashboard(layout())
```

### Complex

```python
from deephaven import ui, time_table
from deephaven.ui import use_memo, use_state
from deephaven.plot.figure import Figure


def use_wave_input():
"""
Demonstrating a custom hook.
Creates an input panel that controls the amplitude, frequency, and phase for a wave
"""
amplitude, set_amplitude = use_state(1.0)
frequency, set_frequency = use_state(1.0)
phase, set_phase = use_state(1.0)

input_panel = ui.flex(
ui.slider(
label="Amplitude",
default_value=amplitude,
min_value=-100.0,
max_value=100.0,
on_change=set_amplitude,
step=0.1,
),
ui.slider(
label="Frequency",
default_value=frequency,
min_value=-100.0,
max_value=100.0,
on_change=set_frequency,
step=0.1,
),
ui.slider(
label="Phase",
default_value=phase,
min_value=-100.0,
max_value=100.0,
on_change=set_phase,
step=0.1,
),
direction="column",
)

return amplitude, frequency, phase, input_panel


@ui.component
def multiwave():
amplitude, frequency, phase, wave_input = use_wave_input()

tt = use_memo(lambda: time_table("PT1s").update("x=i"), [])
t = use_memo(
lambda: tt.update(
[
f"y_sin={amplitude}*Math.sin({frequency}*x+{phase})",
f"y_cos={amplitude}*Math.cos({frequency}*x+{phase})",
f"y_tan={amplitude}*Math.tan({frequency}*x+{phase})",
]
),
[amplitude, frequency, phase],
)
p_sin = use_memo(
lambda: Figure().plot_xy(series_name="Sine", t=t, x="x", y="y_sin").show(), [t]
)
p_cos = use_memo(
lambda: Figure().plot_xy(series_name="Cosine", t=t, x="x", y="y_cos").show(),
[t],
)
p_tan = use_memo(
lambda: Figure().plot_xy(series_name="Tangent", t=t, x="x", y="y_tan").show(),
[t],
)

return ui.column(
ui.row(
ui.stack(
ui.panel(wave_input, title="Wave Input"),
ui.panel(t, title="Wave Table"),
activeItemIndex=0,
),
height=25,
),
ui.row(
ui.stack(ui.panel(p_sin, title="Sine"), width=50),
ui.stack(ui.panel(p_cos, title="Cosine"), width=30),
ui.stack(ui.panel(p_tan, title="Tangent")),
),
)


mw = ui.dashboard(multiwave())
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add autodoc string.

Should we auto doc row, column, stack and panel all on this page? @mattrunyon @mofojed @jnumainville ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added but leaving unresolved so others can see comment

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dsmmcken I think we should document row/column/stack here, as it doesn't make sense outside of the dashboard context. Precedent would be similar to Radio in the Spectrum docs, as it doesn't make sense outside of RadioGroup so they document it there: https://react-spectrum.adobe.com/react-spectrum/RadioGroup.html#radio-props
I could see panel being separate since you can create a panel without a dashboard.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use row and column within a panel currently. They are basically an alias for flex row and flex column, but they don't have the other props of flex

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, panel gets it's own page, but row/col/stack can go under this.

## API Reference

```{eval-rst}
.. dhautofunction:: deephaven.ui.dashboard
```

### Row API Reference

```{eval-rst}
.. dhautofunction:: deephaven.ui.row
```

...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to mention in the flex page that row/column are aliases for flex(..., direction='row') and flex(..., direction='column') when used within a panel? You can't adjust things like flex-wrap or align-items, but they are meant to be simple versions of flex

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made note of this in the current flex docs PR to wait until this discussion is resolved

Copy link
Contributor Author

@ethanalvizo ethanalvizo Oct 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Separate panel docs captured in #922

Loading