plotly / plotly.py

The interactive graphing library for Python :sparkles: This project now includes Plotly Express!
https://plotly.com/python/
MIT License
16.09k stars 2.54k forks source link

Contour or heatmap traces disappear in animations #2151

Open emmanuelle opened 4 years ago

emmanuelle commented 4 years ago

For example https://community.plot.ly/t/fix-contour-plot-in-animation/33558, probably a js issue but need to be investigated first.

mtwichan commented 4 years ago

This issue came up at a workshop I recently did. Here's some sample code for debugging the issue:

import plotly.graph_objs as go

slider_vals = ["1", "2", "3", "4", "5", "6"]
z = [[10, 10.625, 12.5, 15.625, 20],
           [5.625, 6.25, 8.125, 11.25, 15.625],
           [2.5, 3.125, 5., 8.125, 12.5],
           [0.625, 1.25, 3.125, 6.25, 10.625],
           [0, 0.625, 2.5, 5.625, 10]]

fig_dict = {
    "data": [],
    "layout": {},
    "frames": []
}

# fill in most of layout
fig_dict["layout"]["sliders"] = {
    "args": [
        "transition", {
            "duration": 400,
            "easing": "cubic-in-out"
        }
    ],
    "initialValue": "1",
    "plotlycommand": "animate",
    "values": slider_vals,
    "visible": True
}
fig_dict["layout"]["updatemenus"] = [
    {
        "buttons": [
            {
                "args": [None, {"frame": {"duration": 500, "redraw": False},
                                "fromcurrent": True, "transition": {"duration": 300,
                                                                    "easing": "quadratic-in-out"}}],
                "label": "Play",
                "method": "animate"
            },
            {
                "args": [[f'{k}' for k in range(10)], {"frame": {"duration": 0, "redraw": False},
                                  "mode": "immediate",
                                  "transition": {"duration": 0}}],
                "label": "Pause",
                "method": "animate"
            }
        ],
        "direction": "left",
        "pad": {"r": 10, "t": 87},
        "showactive": False,
        "type": "buttons",
        "x": 0.1,
        "xanchor": "right",
        "y": 0,
        "yanchor": "top"
    }
]

sliders_dict = {
    "active": 0,
    "yanchor": "top",
    "xanchor": "left",
    "currentvalue": {
        "font": {"size": 20},
        "prefix": "Slider Index:",
        "visible": True,
        "xanchor": "right"
    },
    "transition": {"duration": 300, "easing": "cubic-in-out"},
    "pad": {"b": 10, "t": 50},
    "len": 0.9,
    "x": 0.1,
    "y": 0,
    "steps": []
}

# make line data 1
data_dict = {
    "x": [1, 2, 3 , 4, 5],
    "y": [1, 2, 3 , 4, 5],
    "mode": "lines",
}

# make line data 2
data_dict = {
    "x": [6, 7, 8, 9, 10],
    "y": [6, 7, 8, 9, 10],
    "mode": "lines",
}

# make contour data
data_dict_contour = {
    "x": [6, 7, 8, 9, 10],
    "y": [6, 7, 8, 9, 10],
    "z": [[10, 10.625, 12.5, 15.625, 20],
           [5.625, 6.25, 8.125, 11.25, 15.625],
           [2.5, 3.125, 5., 8.125, 12.5],
           [0.625, 1.25, 3.125, 6.25, 10.625],
           [0, 0.625, 2.5, 5.625, 10]],
    "type": "contour",
}

fig_dict["data"].append(data_dict)
# fig_dict["data"].append(data_dict_two)
fig_dict["data"].append(data_dict_contour)

# make line frame 1
for idx in range(1, 5):
    frame = {"data": [], "name": str(idx), "traces":[0]}

    data_dict_itr = {
            "x": data_dict["x"][:idx + 1],
            "y": data_dict["y"][:idx + 1],
            "mode": "lines",
        }
    frame["data"].append(data_dict_itr)
    fig_dict["frames"].append(frame)

# make line frame 2
# for idx in range(1, 5):
#     frame = {"data": [], "name": str(idx + 5), "traces":[1]}

#     data_dict_itr = {
#             "x": data_dict_two["x"][:idx + 1],
#             "y": data_dict_two["y"][:idx + 1],
#             "mode": "lines",
#         }
#     frame["data"].append(data_dict_itr)
#     fig_dict["frames"].append(frame)

# make contour frame
for idx in range(1, 5):
    frame = {"data": [], "name": str(idx + 5), "traces": [1]}

    data_dict_itr_two = {
    "x": data_dict["x"],
    "y": data_dict["y"],
    "z": z[:idx],
    "type": "contour",
    }
    frame["data"].append(data_dict_itr_two)
    fig_dict["frames"].append(frame)

# make slider steps
for idx in range(10):
    slider_step = {"args": [
        [str(idx)],
        {"frame": {"duration": 300, "redraw": False},
         "mode": "immediate",
         "transition": {"duration": 300}}
    ],
        "label": str(idx),
        "method": "animate"}
    sliders_dict["steps"].append(slider_step)

fig_dict["layout"]["sliders"] = [sliders_dict]

fig = go.Figure(fig_dict)

fig.show()

It seems to work fine with another trace but using a contour plot causes it to disappear. Uncomment the code with line frame 2 to test another line.

plotly_graph_glitch

Game4Move78 commented 1 year ago

The only "workaround" I could find was to add a slider with redraw set to True in slider steps, and wait momentarily for contour plot to reappear when examining each frame. Obviously not ideal to have a flickering static Contour plot in the background when moving between frames.