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

Introducing an updating text label causes inadvertent plotly figure reset #4186

Open
duane-space opened this issue Jan 8, 2025 · 5 comments
Labels
bug Something isn't working

Comments

@duane-space
Copy link

duane-space commented Jan 8, 2025

Description

I am trying to create a page with dynamic text labels and a plotly timeline figure. I had all of the plotly functionality working as intended, prior to the introduction of a dynamically updating text label.

See the following attempt at a minimally reproducible example. If one changes the x scale zoom of the figure to not show all of the tasks, the plotly figure will automatically reset to once again show the full range. If the second ui.timer call (which only updates the text label) is commented out, this no longer happens and the user selected zoom persists

from nicegui import ui
from datetime import datetime, timedelta
import plotly.express as px
import pandas as pd

df = pd.DataFrame({
    "Task": ["A", "B", "C"],
    "Start": [datetime.now(), datetime.now() + timedelta(hours=1), datetime.now() + timedelta(hours=2)],
    "Finish": [datetime.now() + timedelta(hours=1), datetime.now() + timedelta(hours=2), datetime.now() + timedelta(hours=3)],
})

def initialize_figure():
    now = datetime.now()
    fig = px.timeline(
        df,
        x_start="Start",
        x_end="Finish",
        y="Task",
    )
    fig.add_shape(
        dict(
            type="line",
            x0=now,
            x1=now,
            yref="paper",
            y0=0,
            y1=1,
            line=dict(color="red", dash="dash"),
        )
    )
    fig.update_layout(uirevision="constant",       
                        xaxis=dict(
                        rangeslider=dict(visible=True),
                        type="date",
                    )
    )
    return fig

def update_now_line(fig, plot):
    now = datetime.now()
    for shape in fig.layout.shapes:
        if getattr(shape, 'type', None) == 'line':
            shape.x0 = now
            shape.x1 = now
    plot.update_figure(fig)

def update_time_label(label):
    label.text = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

time_label = ui.label(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
fig = initialize_figure()
plot = ui.plotly(fig)

ui.timer(5.0, lambda: update_now_line(fig, plot))
ui.timer(1.0, lambda: update_time_label(time_label))

ui.run()

I'm using nicegui 2.8.1. I scanned the release notes and didn't see any relevant updates. Is this behavior understood and/or expected? if so, is there a work around?

Thanks

@duane-space
Copy link
Author

duane-space commented Jan 8, 2025

I suspected I would be able to reduce the example further by removing all of the code to support the now line on the plotly figure, but I've actually just discovered that commenting out the first timer (to move the now line) actually resolves the behavior. So it might be some interaction between the two timers?

Nevermind, the following example combining the two updates into just one timer has the same behaviour. It can be resolved simply by commenting out the line to update the time label in update_time(). Seems odd.

from nicegui import ui
from datetime import datetime, timedelta
import plotly.express as px
import pandas as pd

df = pd.DataFrame({
    "Task": ["A", "B", "C"],
    "Start": [datetime.now(), datetime.now() + timedelta(hours=1), datetime.now() + timedelta(hours=2)],
    "Finish": [datetime.now() + timedelta(hours=1), datetime.now() + timedelta(hours=2), datetime.now() + timedelta(hours=3)],
})

def initialize_figure():
    now = datetime.now()
    fig = px.timeline(
        df,
        x_start="Start",
        x_end="Finish",
        y="Task",
    )
    fig.add_shape(
        dict(
            type="line",
            x0=now,
            x1=now,
            yref="paper",
            y0=0,
            y1=1,
            line=dict(color="red", dash="dash"),
        )
    )
    fig.update_layout(uirevision="constant",       
                        xaxis=dict(
                        rangeslider=dict(visible=True),
                        type="date",
                    )
    )
    return fig

def update_time():
    now = datetime.now()
    time_label.text = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    for shape in fig.layout.shapes:
        if getattr(shape, 'type', None) == 'line':
            shape.x0 = now
            shape.x1 = now
    plot.update_figure(fig)

time_label = ui.label(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
fig = initialize_figure()
plot = ui.plotly(fig)

ui.timer(1.0, lambda: update_time())

ui.run()

@duane-space
Copy link
Author

duane-space commented Jan 8, 2025

Might be the same issue underlying #4182 ?

@falkoschindler
Copy link
Contributor

falkoschindler commented Jan 8, 2025

Thanks for reporting this issue, @duane-space!

It might indeed be related to #4182, but I'm not sure.

I just boiled it down to this:

plot = ui.plotly({'layout': {'uirevision': 'constant'}})
ui.button('Update plot', on_click=plot.update)

label = ui.label('...')
ui.button('Update label', on_click=lambda: label.set_text(label.text + '.'))

If you update the label before updating the plot, the layout option {'uirevision': 'constant'} seems to be ignored.

Maybe both problems, #4182 and this #4186, are caused by some rendering procedure in the browser, because an update to one element causes the window and, thus, the other elements to re-adjust.

@falkoschindler falkoschindler added the bug Something isn't working label Jan 8, 2025
@falkoschindler
Copy link
Contributor

Oh, like in #4182, resizing the browser window vertically causes the problem as well, even without a label.

@duane-space
Copy link
Author

Thanks @falkoschindler!

This issue ticket from the plotly repo sounds like it may be the same behavior plotly/plotly.py#3951

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants