hoffstadt / DearPyGui

Dear PyGui: A fast and powerful Graphical User Interface Toolkit for Python with minimal dependencies
https://dearpygui.readthedocs.io/en/latest/
MIT License
13.31k stars 691 forks source link

Reproduce epezent/ImPlot Table Line Plot Demo for EMG #2257

Open jhgorse opened 10 months ago

jhgorse commented 10 months ago

This gif from epezent/implot https://raw.githubusercontent.com/wiki/epezent/implot/screenshots3/tables.gif

Is used at the end of the DPG documentation for Plots https://dearpygui.readthedocs.io/en/latest/documentation/plots.html

Has this been implemented in DPG? If not, perhaps this belongs as an issue or community challenged to reproduce in DPG and compare to the C++ ImPlot original.

Necessary Assets

v-ein commented 10 months ago

Has this been implemented in DPG?

I can't tell for sure but I bet it hasn't. Just because nobody really needed it. It's basically a set of shade series in a table. A single row includes a couple of text labels and a plot with a shade series, axes hidden, and data being updated at regular intervals. Easy to do on your own.

v-ein commented 10 months ago

This is as far as I would care to go:

from random import randrange
import time
import dearpygui.dearpygui as dpg

dpg.create_context()
dpg.create_viewport(title="Test", width=600, height=500)

dpg.setup_dearpygui()
with dpg.window() as w:
    TOTAL_VALUES = 50
    x_values = [i for i in range(TOTAL_VALUES)]
    y_values = [0] * TOTAL_VALUES
    last_update = time.time()

    def update_data():
        global y_values, last_update

        # Make sure we're not too fast
        if time.time() - last_update < 0.03:
            return
        last_update = time.time()

        y_values = y_values[1:]
        y_values.append(randrange(0, 10))
        dpg.configure_item("data-row-1", y1=y_values)
        dpg.fit_axis_data("data-y-axis-1")

    with dpg.item_handler_registry() as handlers:
        dpg.add_item_visible_handler(callback=update_data)

    with dpg.plot(height=50, no_box_select=True, no_mouse_pos=True):
        dpg.bind_item_handler_registry(dpg.last_item(), handlers)

        xaxis = dpg.add_plot_axis(dpg.mvXAxis, no_tick_marks=True, no_tick_labels=True, no_gridlines=True)
        with dpg.plot_axis(dpg.mvYAxis, tag="data-y-axis-1", no_tick_marks=True, no_tick_labels=True, no_gridlines=True):
            dpg.add_shade_series(x_values, y_values, tag="data-row-1")
        dpg.fit_axis_data(xaxis)

dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context()

2257-shadow-series

jhgorse commented 10 months ago

The original uses a trick to reduce the area between the plot area and the widget frame: ImPlot::PushStyleVar(ImPlotStyleVar_PlotPadding, ImVec2(0,0));

which might translate to: dpg.add_theme_style(dpg.mvPlotStyleVar_PlotPadding, 0, 0)

which appears to have no effect:

image

xref:

  1. https://github.com/search?q=repo%3Ahoffstadt%2FDearPyGui+ImPlotStyleVar_PlotPadding&type=code
  2. https://github.com/hoffstadt/DearPyGui/blob/c9d6a91fd579c4b1d01c9835ecb3ad57449378c3/src/mvThemes.cpp#L527
  3. https://github.com/hoffstadt/DearPyGui/blob/c9d6a91fd579c4b1d01c9835ecb3ad57449378c3/dearpygui/demo.py#L308

Code

    with dpg.item_handler_registry() as handlers:
        dpg.add_item_visible_handler(callback=update_data)

# added code
    with dpg.theme(tag="plot_theme"):
        with dpg.theme_component(0):
            dpg.add_theme_style(dpg.mvPlotStyleVar_PlotPadding, 0, 0)

# plot code
    with dpg.plot(height=50, no_box_select=True, no_mouse_pos=True):
        dpg.bind_item_handler_registry(dpg.last_item(), handlers)
v-ein commented 10 months ago

Add category=dpg.mvThemeCat_Plots to add_theme_style(). Also don't forget to bind the theme to the plot with bind_item_theme.

v-ein commented 10 months ago
    with dpg.theme() as plot_theme:
        with dpg.theme_component(0):
            dpg.add_theme_style(dpg.mvPlotStyleVar_PlotPadding, 0, 0, category=dpg.mvThemeCat_Plots)

    with dpg.plot(height=30, no_box_select=True, no_mouse_pos=True):
        dpg.bind_item_handler_registry(dpg.last_item(), handlers)
        dpg.bind_item_theme(dpg.last_item(), plot_theme)
jhgorse commented 10 months ago

Thank you. It does work. image image

@v-ein is there documentation for this programming model? I have not yet grokked the finer details of the python mapping to the original c++ library.

Cheers, Joe

v-ein commented 10 months ago

All the docs I know of are at https://dearpygui.readthedocs.io/en/latest/.

It differs from Dear ImGui in that it's not an immediate-mode GUI (in my opinion): it's rather a regular "stateful" UI that uses the immediate-mode Dear ImGui as its backend. So like in other stateful UIs, you have a tree of widgets and each widget has some properties that you can configure. Looks quite similar to wxWidgets and many other GUI frameworks. However, the immediate-mode backend does lead to certain oddities, like being unable to get widget size until it renders at least once (or for auto-sizing containers, more than once), or widgets "shadowing" each other in a weird way if they overlap.

If you have further questions on DPG, I'd highly recommend asking on Discord - it typically has a quicker turnaround.