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

feat: UI dashboard #176

Merged
merged 13 commits into from
Jan 26, 2024
Merged

feat: UI dashboard #176

merged 13 commits into from
Jan 26, 2024

Conversation

mattrunyon
Copy link
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
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
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
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

plugins/ui/src/js/src/layout/Column.tsx Outdated Show resolved Hide resolved
plugins/ui/src/js/src/layout/Dashboard.tsx Outdated Show resolved Hide resolved
plugins/ui/src/js/src/layout/Row.tsx Outdated Show resolved Hide resolved
plugins/ui/src/deephaven/ui/components/__init__.py Outdated Show resolved Hide resolved
plugins/ui/src/deephaven/ui/components/dashboard.py Outdated Show resolved Hide resolved
plugins/ui/src/deephaven/ui/components/make_dashboard.py Outdated Show resolved Hide resolved
plugins/ui/src/deephaven/ui/object_types/DashboardType.py Outdated Show resolved Hide resolved
plugins/ui/src/js/src/DashboardPlugin.tsx Outdated Show resolved Hide resolved
plugins/ui/src/js/src/DashboardPlugin.tsx Outdated Show resolved Hide resolved
plugins/ui/src/js/src/DocumentUtils.tsx Outdated Show resolved Hide resolved
@mattrunyon mattrunyon marked this pull request as ready for review January 22, 2024 16:04
plugins/ui/src/deephaven/ui/elements/DashboardElement.py Outdated Show resolved Hide resolved
plugins/ui/src/deephaven/ui/components/dashboard.py Outdated Show resolved Hide resolved
):
"""
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
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
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

plugins/ui/src/js/src/DashboardPlugin.tsx Outdated Show resolved Hide resolved
plugins/ui/src/js/src/DashboardPlugin.tsx Outdated Show resolved Hide resolved
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
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment