Skip to content

feat: UI dashboard#176

Merged
mattrunyon merged 13 commits intodeephaven:mainfrom
mattrunyon:ui-dashboard
Jan 26, 2024
Merged

feat: UI dashboard#176
mattrunyon merged 13 commits intodeephaven:mainfrom
mattrunyon:ui-dashboard

Conversation

@mattrunyon
Copy link
Copy Markdown
Collaborator

@mattrunyon mattrunyon commented Dec 14, 2023

Closes #148, closes #149, closes #126, closes #62

Working on web-client-ui changes to support this. Right now the dashboaord will replace the existing layout and width/height won't work because of how golden-layout handles calculating size. Those will be addressed in web-client-ui.

Example code

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())

@mattrunyon mattrunyon self-assigned this Dec 14, 2023
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We'll need an example of course

Comment on lines +29 to +37
const parent = useParentItem();

log.debug2('Rendering panel', panelId);

useEffect(
() => () => {
if (isPanelOpenRef.current) {
log.debug('Closing panel', panelId);
LayoutUtils.closeComponent(layoutManager.root, { id: panelId });
LayoutUtils.closeComponent(parent, { id: panelId });
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Any reason to do it like this instead of doing a parent.addChild as we're doing with Column and Row?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Keeping the LayoutUtils.openComponent at least should retain the behavior of finding a stack w/ the same type of component when we're just opening individual panels/components. When it's within a dh.ui dashboard, then specify the root as the parent (should always be a stack) so we get the layout right

Comment thread plugins/ui/src/js/src/layout/Column.tsx Outdated
Comment thread plugins/ui/src/js/src/layout/Dashboard.tsx Outdated
Comment thread plugins/ui/src/js/src/layout/Row.tsx Outdated
Comment thread plugins/ui/src/deephaven/ui/components/__init__.py Outdated
Comment thread plugins/ui/src/deephaven/ui/components/dashboard.py Outdated
Comment thread plugins/ui/src/deephaven/ui/components/make_dashboard.py Outdated
Comment thread plugins/ui/src/deephaven/ui/object_types/DashboardType.py Outdated
Comment thread plugins/ui/src/js/src/DashboardPlugin.tsx Outdated
Comment thread plugins/ui/src/js/src/DashboardPlugin.tsx Outdated
Comment thread plugins/ui/src/js/src/DocumentUtils.tsx Outdated
@mattrunyon mattrunyon requested a review from mofojed January 18, 2024 20:10
@mattrunyon mattrunyon marked this pull request as ready for review January 22, 2024 16:04
Comment thread plugins/ui/src/deephaven/ui/elements/DashboardElement.py Outdated
Comment thread plugins/ui/src/deephaven/ui/components/dashboard.py Outdated
):
"""
A stack is a container that can be used to group elements which creates a set of tabs.
Each element will get a tab and only one element can be visible at a time.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A question I"m sure that will come up is how do we give a name to the tabs. I'm guessing you need a ui.panel to specify a title. Do we even allow non-ui.panel things here? Should we enforce only passing in PanelElements as the children?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yes you'd need to use a panel w/ the title param

In this first pass we don't allow non panels here. This would be something we consider auto-wrapping in an update to make it nicer to use. I think it's reasonable to allow ui.stack(some_table, some_other_table) if you're fine with the default panel titles

Comment thread plugins/ui/src/js/src/DashboardPlugin.tsx Outdated
Comment thread plugins/ui/src/js/src/DashboardPlugin.tsx Outdated
@mattrunyon mattrunyon requested a review from mofojed January 23, 2024 23:44
mofojed
mofojed previously approved these changes Jan 24, 2024
mattrunyon added a commit to deephaven/web-client-ui that referenced this pull request Jan 26, 2024
Fixes #1683

Test with the dh.ui plugin from
deephaven/deephaven-plugins#176

Example dashboard code

```
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())
```
@mattrunyon mattrunyon merged commit 6adef9c into deephaven:main Jan 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment