canvasXpress icon indicating copy to clipboard operation
canvasXpress copied to clipboard

graphType Network crashed when user shift rendered pictute with LMB

Open glempi opened this issue 11 months ago • 7 comments

Initially graph rendered ok. Crash is occured after user holding left mouse button and moving it (to shift rendered picture in viewport)

javascript callstack on crash:

Screenshot_20240303_004227 you can see that node.layout.displaycement field is undefined.

to reproduce you can use python script and json data which python script used

data network.json

from canvasxpress.canvas import CanvasXpress
import json
import math
from dash import Dash, html
from canvasxpress.render.dash import CXElementFactory


with open("network.json", "r") as f:
    data = json.loads(f.read())

cx = CanvasXpress(
    render_to = "test",
    data = data,
    config = {

        "background": "rgb(100,255,255)",
        "calculateLayout": True,
        "networkLayoutType": "forceDirected",
        "graphType": "Network",

    },

    width = 1400,
    # height = 800
)


g_app = Dash(__name__)

g_app.layout = html.Div(
            id="cx-container",
            style={"textAlign": "center"},
            children=CXElementFactory.render(cx),
        )

if __name__ == "__main__":
    g_app.run_server(debug=True)

glempi avatar Mar 02 '24 16:03 glempi

I can't reproduce . I am asking a collaborator to check. Sorry for the delay.

neuhausi avatar Mar 06 '24 22:03 neuhausi

@docinfosci can you check - script is in python

cb4ds avatar Mar 07 '24 04:03 cb4ds

Thanks! I am confirming that I've seen this and will investigate.

@glempi -- try setting render_to = "" (empty string). This forces CanvasXpress for Python to generate anonymous IDs when passing generated configurations or JavaScript to the Web browser for use by CanvasXpress for JavaScript.

Why?

Dash uses React for its JavaScript, and React requires that UI updates destroy and recreate UI JavaScript objects when updates occur instead of reusing existing objects. But, in this case, an HTML canvas element is also generated using whatever ID is provided. CanvasXpress for JavaScript pays attention to the canvas element ID. There's a moment of opportunity in which CanvasXpress for JavaScript thinks there is still a chart object named the same ID as the canvas element when in fact the DOM/React has disposed of the old object and a new one has yet to be created to take its place—in which case running code can crash. By using anonymous IDs a new ID is assigned to the canvas element with each refresh, so when CanvasXpress for JavaScript attempts to deal with the associated object there is one available and thus avoids the crash. Non-React environments don't have this issue, so in many cases, such as Jupyter Notebooks, using an assigned ID for each chart makes a lot of sense.

Cheers, @docinfosci

docinfosci avatar Mar 07 '24 20:03 docinfosci

Funny about the React philosophy. Why would you want to reuse/fix an existing/old object if I can buy a brand new one. (Pretty much the American mentality :-) :-) :-)

neuhausi avatar Mar 07 '24 20:03 neuhausi

So true! It's maddening. I've been considering whether chart rendering for a Dash context should force anonymity, or whether a warning should be printed in the logs. For now, education seems the better approach as it avoids other issues like, for example, people not understanding why custom JavaScript can't find their object by ID.

docinfosci avatar Mar 07 '24 22:03 docinfosci

Thanks! I am confirming that I've seen this and will investigate.

@glempi -- try setting render_to = "" (empty string). This forces CanvasXpress for Python to generate anonymous IDs when passing generated configurations or JavaScript to the Web browser for use by CanvasXpress for JavaScript.

Why?

Dash uses React for its JavaScript, and React requires that UI updates destroy and recreate UI JavaScript objects when updates occur instead of reusing existing objects. But, in this case, an HTML canvas element is also generated using whatever ID is provided. CanvasXpress for JavaScript pays attention to the canvas element ID. There's a moment of opportunity in which CanvasXpress for JavaScript thinks there is still a chart object named the same ID as the canvas element when in fact the DOM/React has disposed of the old object and a new one has yet to be created to take its place—in which case running code can crash. By using anonymous IDs a new ID is assigned to the canvas element with each refresh, so when CanvasXpress for JavaScript attempts to deal with the associated object there is one available and thus avoids the crash. Non-React environments don't have this issue, so in many cases, such as Jupyter Notebooks, using an assigned ID for each chart makes a lot of sense.

Cheers, @docinfosci

Unfortunately render_to="" doesn't help layout.displacement property still undefined after shifting viewport

Screenshot_20240308_174118

glempi avatar Mar 08 '24 09:03 glempi

Is this completed?

neuhausi avatar Apr 25 '24 22:04 neuhausi