Cytoscape layout transform option

Has anyone had success using the “transform” option of some of the cytoscape layout options. If I pass in a python function I get an “Error loading layout.” Here’s the traceback:

Traceback (most recent call last):
  File "C:\Users\joshua.super\AppData\Local\Programs\Python\Python39\Lib\site-packages\flask\app.py", line 2091, in __call__
    return self.wsgi_app(environ, start_response)
  File "C:\Users\joshua.super\AppData\Local\Programs\Python\Python39\Lib\site-packages\flask\app.py", line 2076, in wsgi_app
    response = self.handle_exception(e)
  File "C:\Users\joshua.super\AppData\Local\Programs\Python\Python39\Lib\site-packages\flask\app.py", line 2073, in wsgi_app
    response = self.full_dispatch_request()
  File "C:\Users\joshua.super\AppData\Local\Programs\Python\Python39\Lib\site-packages\flask\app.py", line 1518, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "C:\Users\joshua.super\AppData\Local\Programs\Python\Python39\Lib\site-packages\flask\app.py", line 1516, in full_dispatch_request
    rv = self.dispatch_request()
  File "C:\Users\joshua.super\AppData\Local\Programs\Python\Python39\Lib\site-packages\flask\app.py", line 1502, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
  File "C:\Users\joshua.super\AppData\Local\Programs\Python\Python39\Lib\site-packages\dash\dash.py", line 659, in serve_layout
    to_json(layout),
  File "C:\Users\joshua.super\AppData\Local\Programs\Python\Python39\Lib\site-packages\dash\_utils.py", line 22, in to_json
    return to_json_plotly(value)
  File "C:\Users\joshua.super\AppData\Local\Programs\Python\Python39\Lib\site-packages\plotly\io\_json.py", line 124, in to_json_plotly
    return json.dumps(plotly_object, cls=PlotlyJSONEncoder, **opts)
  File "C:\Users\joshua.super\AppData\Local\Programs\Python\Python39\Lib\json\__init__.py", line 234, in dumps
    return cls(
  File "C:\Users\joshua.super\AppData\Local\Programs\Python\Python39\Lib\site-packages\_plotly_utils\utils.py", line 59, in encode
    encoded_o = super(PlotlyJSONEncoder, self).encode(o)
  File "C:\Users\joshua.super\AppData\Local\Programs\Python\Python39\Lib\json\encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "C:\Users\joshua.super\AppData\Local\Programs\Python\Python39\Lib\json\encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "C:\Users\joshua.super\AppData\Local\Programs\Python\Python39\Lib\site-packages\_plotly_utils\utils.py", line 136, in default
    return _json.JSONEncoder.default(self, obj)
  File "C:\Users\joshua.super\AppData\Local\Programs\Python\Python39\Lib\json\encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type function is not JSON serializable

I’m just curious if anyone has found a work-around. Is there some sort of dict or string that I could pass in instead of a true python function?

Reference:
Cytoscape.js

Maybe you could use a clientside callback- which is written in js.

1 Like

Yes that works, here is an example:

from dash import html, Output,State, Input, Dash, no_update ,dcc, ClientsideFunction
import dash_cytoscape as cyto
import json

app = Dash(__name__)

app.layout = html.Div([
    cyto.Cytoscape(
        id='cytoscape',
        style={'width': '100%', 'height': '400px'},
        stylesheet = [
            {
                'selector': 'node',
                'style': {
                    'label': 'data(label)',
                    'font-size': '50px',
                    'text-valign': 'center',
                    'text-halign': 'right',
                    'color': 'white',
                    'text-outline-width': '2px',
                    "text-wrap": "wrap",
                    'width': 'data(size)',
                    'height': 'data(size)',
                    "text-wrap": "wrap"
                }}
                
            ],
        elements=[
            # Define your nodes here with unique IDs
            {'data': {'id': 'node1','size':'150px', 'label': 'Node 1'}, "position":{"x":-200, "y":0}},
            {'data': {'id': 'node2','size':'150px', 'label': 'Node 2'}, "position":{"x":-20, "y":0}},
            {'data': {'id': 'node3','size':'150px', 'label': 'Node 3'}, "position":{"x":200, "y":0}},
        ],
        layout= {'name' : 'preset'}
    ),
    html.Button('Client-Side Callback', id='client-button'),
])

app.clientside_callback(
'''
function (n){
    let layout = {};
    layout.name = 'preset';
    layout.transform = (node, position) => {
        console.log("Transform function called");
    
        console.log("Position before:", position);
        position.x += 20;
 
        return position;
    };
    return layout;
}
''',
    Output('cytoscape', 'layout'),
    Input('client-button', 'n_clicks'),
    pevent_initial_call = True
)


if __name__ == "__main__":
    app.run_server(debug=True)
2 Likes

Thank you, this seems to be working except for the console.log lines but maybe I’m just not looking in the right place. It would be very useful to be able to print some stuff. Where does that console.log statement print to for you?

You can find these in your browser console under: tools for web developers → console