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.63k stars 669 forks source link

to run bind_item_theme out of loop #2232

Closed sailfish009 closed 7 months ago

sailfish009 commented 7 months ago

Is your feature request related to a problem? Please describe. While testing the right alignment of table cells, I saw the following phenomenon. I am displaying a Pandas dataframe in a table with 64 columns and 1000 rows, and I was previously applying the button theme to 4 columns, and it was taking about 20 to 25 seconds to load the data. Currently, I am applying the button theme to 13 out of 64 columns. This is to make the cells right-align and pop-up window behavior. There is no difference except that the number of themes applied to the columns has increased, but the time taken has increased significantly to about 89 to 95 seconds. Of course, if I am not loading the entire Pandas dataframe, but only 64 rows, the time taken is about 0.5 seconds, which is not a problem.

Describe the solution you'd like I would like to be able to call the bind_item_theme function outside of the loop like this, or I would like to be able to apply the theme by a specific column. If I apply the theme by cell, it is a double loop, but if it is by column, I think it will take a little longer.

with dpg.window(tag="Primary Window"):
    with dpg.table(label='DataFrameTable'):
        for i in range(df.shape[1]):
            dpg.add_table_column(label=df.columns[i])
        for i in range(df.shape[0]):
            with dpg.table_row():
                for j in range(df.shape[1]):
                    if j == 3:
                        b = dpg.add_button(label=f"{arr[i,j-3]}/{arr[i,j]}", width=100)
                        dpg.bind_item_theme(b, "__button_right")
                    else:
                        dpg.add_button(label=f"{arr[i,j]}") 

Describe alternatives you've considered As it stands, the only way to do this is to avoid loading the entire data at once. (lazy eval, generator?)

Additional context None

v-ein commented 7 months ago

Text alignment only applies to buttons. Can you use add_text for left-aligned content and add_button for right-aligned content? This way you only need to update the theme once, to the table itself.

sailfish009 commented 7 months ago

I'm currently applying 2 different themes and 1 text to a cell. The strings to which the right theme applies are numbers. It has a comma and a decimal mark, and the theme on the left is the general English text.

As a result, I want to apply the right-align theme only to a specific row in a specific column, but it doesn't work properly when I actually apply it. The reason for applying it to a column is that if you apply it to a cell with a large number of rows, it will take too long. If we could only apply the theme to the current row of the screen, we would be able to reduce the loading time significantly. But at the moment, I don't know exactly how. I think I can make good use of lazy eval.

start_time = time.time()
with dpg.window(tag="Primary Window"):
    with dpg.table(label='DataFrameTable'):
        for i in range(df.shape[1]):
            c = dpg.add_table_column(label=df.columns[i])
            # if i in [3, 5, 7, 9, 11, 13]:                                 
            #    dpg.bind_item_theme(c, "__button_right_blue_text")         # try to bind theme to column (due to slow loading time), not working
            # elif i in [14, 16, 18, 20, 22, 24, 26]:
            #     dpg.bind_item_theme(c, "__button_right_black_text")       # not working

        for i in range(df.shape[0]):
            with dpg.table_row():
                for j in range(df.shape[1]):
                    if j in [3, 5, 7, 9, 11, 13]:
                        b = dpg.add_button(label=f"{arr[i,j-3]}/{arr[i,j]}", width=-1)
                        dpg.bind_item_theme(b, "__button_right_blue_text")  # clickable text for callback to popup window 
                    elif j in [14, 16, 18, 20, 22, 24, 26]:
                        b = dpg.add_button(label=f"{arr[i,j-7]}/{arr[i,j]}", width=-1)
                        dpg.bind_item_theme(b, "__button_right_black_text") # normal text, right aligned

                    else:
                        dpg.add_text(f"{arr[i,j]}")                         # normal text, left aligned

print(f'time: {time.time() - start_time} ')
v-ein commented 7 months ago

By applying "__button_right_black_text" to the entire table and overriding it with "__button_right_blue_text" in cells [3, 5, 7, 9, 11, 13] you can reduce the number of theme bindings in half.

Since there are only two themes for buttons, and you're not using hover effects and the callback on those buttons, you can trick DPG into using two different styles by creating half of those buttons with enabled=False. Then, create only one theme, but add components into it with enabled_state=False for those buttons that are in the disabled state. This way you get two sub-themes in a single theme, and you can bind that single theme to the table itself.

This approach doesn't scale very well, but in your case it will be easier than to implement lazy evaluation. I hope that PR #2113 eventually gets merged and this will allow themes on individual rows and columns. Until that happens, enabled=False will probably "just work" for you.

sailfish009 commented 7 months ago

I took the easiest approach. I added the back and forward buttons and showed the current page and full page. We set the default row to 128 lines and sliced the Pandas dataframe to solve the time lag issue.

It's a workaround, but I don't think it's a big deal since the customer agreed to it.

v-ein commented 7 months ago

Will you close this ticket then? I bet PR #2113 will eventually let you re-implement it without the workaround; until then, I don't see any other ways to solve it.

sailfish009 commented 7 months ago

yes!