Hi there. I describe here a problem that I found not solution so far. Is this a bug?
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:
-
select shape
-
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