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
12.94k stars 676 forks source link

Moving on the axes (without going through each graph first) breaks the other plots. #2367

Open bmrv911 opened 1 month ago

bmrv911 commented 1 month ago

Version of Dear PyGui

Version: 1.11.1 Operating System: Windows 11

My Issue/Question

When viewing a pair of plots, it is necessary to go through each one so that when adjusting the x-axis with buttons (in this case), the other plot(s) don't break. However, pressing the scroll button on the x-axis before scrolling through each plot causes the not-displayed plots to break.

To Reproduce

Steps to reproduce the behavior:

  1. Run the code below.
  2. Scroll the x-axis using the "down", "left" or "right" buttons.
  3. Select the next graph.
  4. See error

Expected behavior

We should see the other graphs with or without pressing the axis shift buttons.

Screenshots/Video

Note that by selecting all the plots, and then scrolling along the x-axis, the scrolling occurs for both plots correctly:

https://github.com/user-attachments/assets/2cefa2cd-6cac-44e4-98a4-719ef0aa5e35

Another observation you can see when running the provided code is that any shift done on the x-axis with a specific graph is assumed to not work the same for the other graphs the more shifts there are.

In this example, you can see that if we first move along the x-axis (without going through each graph previously), the other graphs break:

https://github.com/user-attachments/assets/4dc5279e-0209-402e-9f20-305403e95931

Standalone, minimal, complete and verifiable example

import dearpygui.dearpygui as dpg

dpg.create_context()

def update_plot(sender, app_data):
    dpg.hide_item("plot1")
    dpg.hide_item("plot2")

    if app_data == "Plot 1":
        dpg.show_item("plot1")
    elif app_data == "Plot 2":
        dpg.show_item("plot2")

def left_button():
    current_min, current_max = dpg.get_axis_limits("x1")
    dpg.set_axis_limits("x1", current_min - 1, current_max - 1)
    current_min, current_max = dpg.get_axis_limits("x2")
    dpg.set_axis_limits("x2", current_min - 1, current_max - 1)

def right_button():
    current_min, current_max = dpg.get_axis_limits("x1")
    dpg.set_axis_limits("x1", current_min + 1, current_max + 1)
    current_min, current_max = dpg.get_axis_limits("x2")
    dpg.set_axis_limits("x2", current_min + 1, current_max + 1)

def down_button():
    current_min, current_max = dpg.get_axis_limits("x1")
    dpg.set_axis_limits("x1", current_min + 1, current_max - 1)
    current_min, current_max = dpg.get_axis_limits("x2")
    dpg.set_axis_limits("x2", current_min + 1, current_max - 1)

def up_button():
    current_min, current_max = dpg.get_axis_limits("x1")
    dpg.set_axis_limits("x1", current_min - 1, current_max + 1)
    current_min, current_max = dpg.get_axis_limits("x2")
    dpg.set_axis_limits("x2", current_min - 1, current_max + 1)

with dpg.window(label="Main Window", width=700, height=500):
    with dpg.group(horizontal=True):
        dpg.add_button(arrow=True, callback=down_button, direction=dpg.mvDir_Down)
        dpg.add_button(arrow=True, callback=up_button, direction=dpg.mvDir_Up)
        dpg.add_spacer(width=9)
        dpg.add_button(callback=left_button, arrow=True, direction=dpg.mvDir_Left)
        dpg.add_button(callback=right_button, arrow=True, direction=dpg.mvDir_Right)
        dpg.add_spacer(width=9)
        dpg.add_combo(label="Select Plot", items=["Plot 1", "Plot 2"], callback=update_plot, default_value="Plot 1")

    with dpg.plot(label="Plot 1", height=-1, width=-1, tag="plot1"):
        dpg.add_plot_axis(dpg.mvXAxis, label="x", tag="x1")
        dpg.set_axis_limits("x1", 3, 6)
        dpg.set_axis_ticks("x1", label_pairs=(("0", 0), ("1", 1), ("2", 2), ("3", 3), ("4", 4), ("5", 5), ("6", 6)))
        dpg.add_plot_axis(dpg.mvYAxis, label="y", tag="y1")
        dpg.add_line_series([0, 1, 2, 3, 4, 5, 6], [5, 7, 6, 3, 2, 3, 4], label="Line 1", parent="y1")

    with dpg.plot(label="Plot 2", height=-1, width=-1, tag="plot2"):
        dpg.add_plot_axis(dpg.mvXAxis, label="x", tag="x2")
        dpg.set_axis_limits("x2", 3, 6)
        dpg.set_axis_ticks("x2", label_pairs=(("0", 0), ("1", 1), ("2", 2), ("3", 3), ("4", 4), ("5", 5), ("6", 6)))
        dpg.add_plot_axis(dpg.mvYAxis, label="y", tag="plot_2_y")
        dpg.add_line_series([0, 1, 2, 3, 4, 5, 6], [6, 3, 2, 1, 4, 1, 2], label="Line 2", parent="plot_2_y")

    dpg.show_item("plot1")
    dpg.hide_item("plot2")

dpg.create_viewport(title='Custom Title', width=900, height=600)
dpg.setup_dearpygui()
dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context()
v-ein commented 1 month ago

Will it be easier to store current axis limits in a Python field (maybe a global variable) instead of calling get_axis_limits? I bet the issue you're seeing happens because a plot needs to render at least one frame before you can actually use get_axis_limits (that's my guess and I haven't checked it). You can add something like

print(f"{current_min=}, {current_max=}")

to your left_button/right_button/etc. wherever you call get_axis_limits, and see how it works for the visible plot and for plots that have never been displayed. You'll probably see different values. I bet it will print "current_min=0.0, current_max=0.0" for the plot 2.