Avaiga / taipy-gui

Graphical User Interface generator for Taipy
Apache License 2.0
60 stars 20 forks source link

BUG-Charts briefly resets to empty when refreshed #932

Closed gbritoda closed 1 year ago

gbritoda commented 1 year ago

Description Whenever a chart is refreshed, it resets quickly to an empty chart before updating. While this is not very noticeable in faster systems, if there's an slower connection to the GUI or the system is running slow due to handling a lot of data or something, it gets more noticeable. It also gets very noticeable if you have fast updating data, like a live graph tracking something, which is my example below:

How to reproduce In this code, we should have a continuous sine wave on the graph updating every 0.1 second when the button is pressed. But since the graphs blinks every update (the need to refresh is due to Avaiga/taipy#466), it's very hard to read the labels

from taipy.gui import Gui
from time import sleep
from math import sin

data = {
        "x":[],
        "y":[]
    }

page = """
<|button|label=start|on_action=start_button_pressed|>
<|{data}|chart|x=x|y=y|rebuild=True|propagate|>
"""

def start_button_pressed(state):
    global data
    x = 0
    while True:
        data['x'].append(x)
        data['y'].append(sin(x))
        state.refresh("data")
        x+=1
        sleep(0.1)

gui = Gui(page=page)

gui.run(
    host="0.0.0.0",
    port=1234,
    debug=True,
    dark_mode=False,
    use_reloader=True
)

Expected behavior A continuously flowing graph of a sine wave

Runtime environment Please specify relevant indications.

FlorianJacta commented 1 year ago

Could you help me understand the issue at hand? Is the behavior you describe only visible with many points, or is it only due to a change of data?

A part of your issue could be that Taipy will change its x-axis and y-axis depending on the data. You can make the chart axes static. However, I believe you are talking about labels of data points.

Here is an example of code with static axes. Would it help?

from taipy.gui import Gui
from time import sleep
from math import sin

data = {
        "x":[],
        "y":[]
    }

# my layout to have static axis
layout = {
        "xaxis": {
            "range": [0, 100],  
        },
        "yaxis": {
            "range": [-1, 1], 
        }
    }

page = """
<|button|label=start|on_action=start_button_pressed|>
<|{data}|chart|x=x|y=y|layout={layout}|>
"""

def start_button_pressed(state):
    x = 0
    while x < 100:
        data['x'].append(x)
        data['y'].append(sin(x))

        state.data = data # I am using the assignment directly and not the refresh function

        x+=1
        sleep(0.1)

gui = Gui(page=page)
gui.run()

On a side note: The rebuild property is not needed here; it is used when the data changes its structure (for example, when the column names change). Propagate property is also not required.

gbritoda commented 1 year ago

Got my names mixed! Meant axes not labels So what happens is:

That's the output of my code: graph 2 See the flickering?

Your solution makes it less noticeable because the axes don't change. But the graph still blinks everytime its data is refreshed. Hoping it makes sense 😅

FlorianJacta commented 1 year ago

We are looking into this issue currently.

Also, on a side note, it is better to use the ìnvoke_long_callback` function for live data updates as such:

from taipy.gui import Gui, invoke_long_callback
from math import sin
import time

data = {
        "x":[],
        "y":[]
    }

# my layout to have static axis
layout = {
        "xaxis": {
            "range": [0, 100],  
        },
        "yaxis": {
            "range": [-1, 1], 
        }
    }

page = """
<|{data}|chart|x=x|y=y|layout={layout}|>
"""

x = 1

def iddle():
     while True:
          time.sleep(1)

def update(state):
    data = state.data
    data['x'].append(state.x)
    data['y'].append(sin(state.x))

    state.data = data # I am using the assignment directly and not the refresh function

    state.x+=1

def on_init(state):
    invoke_long_callback(state, iddle, [], update, [], 500)

gui = Gui(page=page)
gui.run()