Skip to content

Possible bug in Plotly (python) when dragging and dropping shapes in scatter plots #4723

Open

Description

Hi there. I describe here a problem that I found not solution so far. This seems like a bug

bug01.mp4

Using dash 2.17.1, plotly 5.23.0, python 3.12.4, Windows 11.

Context is: A python app that uses dcc.Graph to create a chart with 4 lines. The x-axis contains datetime values and the y-axis contain floats, and the chart is updated in a dcc.Interval callback using Patch() objects.

The problem is:

  • I draw a shape (line, rect, freeform) on the chart
  • I select the shape
  • I start dragging the shape, move the shape around, and then drop the shape
  • The shape disappears from the chart. The javascript console presents 4 errors (reproduced at the end of this post)

It seems this bug occurs when the x-axis uses datetime. For example, when using int values, the bug does not happen. Here's a sample program to reproduce the error.

from    datetime                import datetime, timedelta
from    dash                    import Dash, dcc, html
import  pandas                  as pd

import  plotly.express          as px

config = {
    'displayModeBar'          : True,
    'modeBarButtonsToAdd'     : ['drawline', 'eraseshape', 'drawrect',  "drawopenpath" ]
}

# ____________________________________
#
#   Sample dataframe with int index

def df_int ():
    index   = [x for x in range(10)]
    y       = [x for x in range(10)]

    return pd.DataFrame (y, index=index)

# ____________________________________
#
#   Sample dataframe with datetime index

def df_datetime():

    now     = datetime.now()
    index   = [now + timedelta(minutes=x) for x in range(10)]
    y       = [x for x in range(10)]

    return pd.DataFrame (y, index=index)

# ____________________________________

df   = df_datetime()
#df  = df_int() 	# uncomment to test with int index

fig = px.line (data_frame= df, x=df.index, y=df.columns[0])

fig.update_layout (uirevision=True)


app         = Dash (__name__)
app.layout  = html.Div ([

                dcc.Graph       (id= "test_chart", config= config, figure= fig),
                dcc.Interval    (id= "interval",   interval= 500)

            ])

# ____________________________________
#
@callback (
    Output ("test_chart",   "figure"),

    Input  ("interval",     "n_intervals"),
    State  ("test_chart",   "figure")

)
def update (n, fig):

    debug_shapes (fig)
    return create_patch()


# ____________________________________
#
def debug_shapes (fig):
    layout = fig['layout']

    if "shapes" not in layout:
        return

    shapes       = layout ['shapes']
    n_shapes     = len (shapes)
    range_shapes = range(n_shapes)

    print ("__________")
    print (f"num shapes: {n_shapes}")

    for i, x in zip (range_shapes, shapes):
        print (f"{i} => {x}")

    print ()

# ____________________________________
#
def create_patch ():
    patch = Patch ()

    # sample update to illustrate the case
    patch ["data"][0]['y'][-1] = 5

    # tried this below, the end result was the same
    #patch ["data"]["layout"]["uirevision"] = True	

    return patch

# ____________________________________
#
if __name__ == "__main__":
    app.run(debug=True)

Other things:

  • This problem also happens if there's no updating to the figure (eg. no update loop for dcc.Interval). There's another thing that happens in the chart, this one I don't know if it's also a bug, or an error in my code:
  1. select shape

  2. try dragging the shape. The shape returns to the original position (before the drag) and stays there, even if I continue to drag movement. When I release the mouse button (to drop the shape), the shape jumps from the original position to this position.

Tested this with int index on x-axis. With datetime x-axis, the shape disappears when releasing the mouse button

  • I wrote debug_shapes to check where the shape ended after it disappeared. The result is something like this (notice that x0 and y0 have None as value):

{'editable': True, 'visible': True, 'showlegend': False, 'legend': 'legend', 'legendgroup': '', 'legendgrouptitle': {'text': '', 'font': {'weight': 'normal', 'style': 'normal', 'variant': 'normal', 'lineposition': 'none', 'textcase': 'normal', 'shadow': 'none'}}, 'legendrank': 1000, 'label': {'text': '', 'texttemplate': ''}, 'xref': 'x', 'yref': 'y', 'layer': 'above', 'opacity': 1, 'line': {'color': '#444', 'width': 4, 'dash': 'solid'}, 'fillcolor': 'rgba(0, 0, 0, 0)', 'fillrule': 'evenodd', 'type': 'rect', 'x0': None, 'y0': 4.7168458781362, 'x1': None, 'y1': 1.017921146953405}

  • The disappearing shape bug does not happen with plotly 5.22.

However, I can't use this version on my project because it contains another bug corrected in 5.23):

  • when I select the pan tool and drags the chart, the chart image gets blank (eg disappears) and appears again when I release the mouse (in line charts using webgl)
  • The javascript console log with the errors:
plotly.min.js:8 ERROR: unrecognized date NaN
a.error @ plotly.min.js:8
e.cleanDate @ plotly.min.js:8
indexOf.t.cleanPos @ plotly.min.js:8
W.coercePosition @ plotly.min.js:8
l @ plotly.min.js:8
t.exports @ plotly.min.js:8
t.exports @ plotly.min.js:8
e.applyContainerArrayChanges @ plotly.min.js:8
Z @ plotly.min.js:8
q @ plotly.min.js:8
(anonymous) @ plotly.min.js:8
e.call @ plotly.min.js:8
M @ plotly.min.js:8
H @ plotly.min.js:8
T @ plotly.min.js:8

plotly.min.js:8 ERROR: unrecognized date NaN
a.error @ plotly.min.js:8
e.cleanDate @ plotly.min.js:8
indexOf.t.cleanPos @ plotly.min.js:8
W.coercePosition @ plotly.min.js:8
l @ plotly.min.js:8
t.exports @ plotly.min.js:8
t.exports @ plotly.min.js:8
e.applyContainerArrayChanges @ plotly.min.js:8
Z @ plotly.min.js:8
q @ plotly.min.js:8
(anonymous) @ plotly.min.js:8
e.call @ plotly.min.js:8
M @ plotly.min.js:8
H @ plotly.min.js:8
T @ plotly.min.js:8

plotly.min.js:8 Error: <path> attribute d: Expected number, "MNaN,121HNaNV215H…".
(anonymous) @ plotly.min.js:8
(anonymous) @ plotly.min.js:8
vt @ plotly.min.js:8
J.each @ plotly.min.js:8
J.attr @ plotly.min.js:8
M @ plotly.min.js:8
w @ plotly.min.js:8
e.applyContainerArrayChanges @ plotly.min.js:8
Z @ plotly.min.js:8
q @ plotly.min.js:8
(anonymous) @ plotly.min.js:8
e.call @ plotly.min.js:8
M @ plotly.min.js:8
H @ plotly.min.js:8
T @ plotly.min.js:8

plotly.min.js:8 Uncaught Error: malformed path data
    at plotly.min.js:8:3295125
    at [Symbol.replace] (<anonymous>)
    at String.replace (<anonymous>)
    at t.exports (plotly.min.js:8:3294858)
    at e.readPaths (plotly.min.js:8:267384)
    at M (plotly.min.js:8:258195)
    at w (plotly.min.js:8:262981)
    at e.applyContainerArrayChanges (plotly.min.js:8:411588)
    at Z (plotly.min.js:8:426560)
    at q (plotly.min.js:8:421733)
(anonymous) @ plotly.min.js:8
t.exports @ plotly.min.js:8
e.readPaths @ plotly.min.js:8
M @ plotly.min.js:8
w @ plotly.min.js:8
e.applyContainerArrayChanges @ plotly.min.js:8
Z @ plotly.min.js:8
q @ plotly.min.js:8
(anonymous) @ plotly.min.js:8
e.call @ plotly.min.js:8
M @ plotly.min.js:8
H @ plotly.min.js:8
T @ plotly.min.js:8

bug02.mp4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    P3backlogbugsomething broken

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions