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

Bug: Exceptions thrown following User Interaction with Annotations on a time axis #4961

Open
bcliang opened this issue Jan 14, 2025 · 1 comment
Labels
bug something broken P2 considered for next cycle

Comments

@bcliang
Copy link

bcliang commented Jan 14, 2025

In my use case, a user may load time-series data into a scatter chart. The user may need to zoom and pan the time axis of the plot (xtickmode='auto' with nticks=#) to better visualize periods of data.

  • Users may wish to annotate the plots (using a rect or line drawing) -- they do so by clicking the annotation buttons on the plotly figure toolbar.
  • In some cases, an annotation is placed incorrectly on the time axis and must be moved/resized. In this case, users select an annotation and then drag-drop as appropriate.

Regression in v5.23.0

  • In plotly.py v5.22.0: when drawing a figure with at least one time axis, annotations could be moved/resized interactively without problem. (expected behavior)
  • With v5.23.0 a regression was introduced. Moving/resizing an annotation will trigger browser exception (ERROR: unrecognized date (NaN)) when working on a time axis. The annotation will disappear from the figure with the exception.
  • minimal reproducible examples below:

This only affects time-axis (no issues when both x- and y-axes are numerical)

import pandas as pd
import plotly.graph_objects as go

df = pd.DataFrame({
        "id": [1, 2, 3, 4, 5],
        "data1": [1, 2, 3, 4, 5],
    })

fig = go.Figure()
fig.add_trace(
    go.Scatter(
        x = df.id,
        y = df.data1
    ),
)
fig.update_layout(title=dict(text="no problems resizing/moving annotations after selection"))

fig.show(config=dict(
        modeBarButtonsToAdd=[
            "drawline",
            "drawrect",
        ],
    ),
)

exceptions when x- or y-axis is a datetime object

Note: also the case with pd.Timestamp object

import pandas as pd
import plotly.graph_objects as go
import datetime

df2 = pd.DataFrame({
        "id": [datetime.datetime(2024, 11, 1 + index) for index in range(5)],
        "data1": [1, 2, 3, 4, 5],
    })

fig2 = go.Figure()
fig2.add_trace(
    go.Scatter(
        x = df2.id,
        y = df2.data1,
    ),
)
fig2.update_layout(title=dict(text="(x axis) invalid date error on resize/move annotation"))
fig2.show(
    config=dict(
        modeBarButtonsToAdd=[
            "drawline",
            "drawrect",
        ],
    ),
)

fig2b = go.Figure()
fig2b.add_trace(
    go.Scatter(
        x = df2.data1,
        y = df2.id
    ),
)
fig2b.update_layout(title=dict(text="(y axis) invalid date error on resize/move annotation"))
fig2b.show(config=dict(
        modeBarButtonsToAdd=[
            "drawline",
            "drawrect",
        ],
    ),
)
@bcliang
Copy link
Author

bcliang commented Jan 14, 2025

Elsewhere (#3065) it was suggested that annotation issues could be resolved by converting the time data to a numeric value (i.e. df2.id.apply(lambda t: t.timestamp())).

However, to get the formatting correct, I would need to specific tickvals and ticktext specified for every point. This doesn't work when there are many data points. In the following example, I manually specify 3 ticks. This cleans up the axis labels and the hover label for those specific points. All other points persist the numeric tick value in the hovertext.

fig2b = go.Figure()
fig2b.add_trace(
    go.Scatter(
        x = df2.data1,
        y = df2.id.apply(lambda t: t.timestamp())
    ),
)
tickvals = df2.id.apply(lambda t: t.timestamp())
fig2b.update_layout(title=dict(text="(y axis) manually specify some ticks (hover info is still incorrect)"), 
    yaxis=dict(
        tickvals=[tickvals.iloc[0], tickvals.iloc[5], tickvals.iloc[-1]], 
        ticktext=[df2.id.iloc[0], df2.id.iloc[5], df2.id.iloc[-1]],
    )
)

fig2b.show(config=dict(
        modeBarButtonsToAdd=[
            "drawline",
            "drawrect",
        ],
    ),
)

@gvwilson gvwilson added bug something broken P2 considered for next cycle labels Jan 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug something broken P2 considered for next cycle
Projects
None yet
Development

No branches or pull requests

2 participants