Skip to content

aalexei/justpy-cytoscape

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 

Repository files navigation

Cytoscape component for JustPy

This is a component for JustPy to place a Cytoscape graph on a page and interact with it.

Base libs:

Installation

Place the javascript component in your applications /static/components/ directory (the default /static/ dir is the directory the application is run form).

Place the python module cytoscape.py somewhere on your python’s PATH.

Easiest way to install is to clone the git repo to /static/src/ and symlink the two files as required above.

Basic Usage

Define a list of nodes and edges, some styling directives, and the layout. Add the component as you would any other JustPy component.

import justpy as jp
from cytoscape import Cytoscape

elements = [
    {'data': { 'id': 'a' }},
    {'data': { 'id': 'b' }},
    {'data': { 'id': 'c' }},
    {'data': { 'id': 'ab', 'source': 'a', 'target': 'b' }},
    {'data': { 'id': 'ac', 'source': 'a', 'target': 'c' }},
  ]

graphstyle = [
    {'selector': 'node',
      'style': {
        'label': 'data(id)'
      }},
    {'selector': 'edge',
      'style': {
        'width': 3,
        'target-arrow-shape': 'triangle',
      }},
  ]

layout = {'name': 'grid', 'rows': 2}

def cyto_test():
    wp = jp.WebPage()
    wp.head_html = '''
    <script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.21.1/cytoscape.min.js"></script>
    '''
    cyto = Cytoscape(a=wp,
                     style = 'background-color: #fefefe; border: 1px solid; width: 400px; height: 400px;',
                     classes='m-2',
                     elements = elements,
                     graphstyle = graphstyle,
                     layout = layout,
                     )
    return wp

jp.justpy(cyto_test)

Calling cytoscape methods

Two methods are defined on Cytoscape class for calling the underlying js methods. The run_method function (from JustPy) and run_method_get_output for collecting results. N.B. you must bind the WebPage’s ‘result_ready’ event to cyto.handle_page_event to receive output.

e.g. adding a button to reset zoom and pan:

async def button_click(self, msg):
    await msg.page.cyto.run_method('reset()', msg.websocket)

def cyto_test():
    wp = jp.WebPage()
    wp.head_html = '''
    <script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.21.1/cytoscape.min.js"></script>
    '''
    wp.cyto = Cytoscape(a=wp,
                     style = 'background-color: #fefefe; border: 1px solid; width: 400px; height: 400px;',
                     classes='m-2',
                     elements = elements,
                     graphstyle = graphstyle,
                     layout = layout,
                     )
    button_classes = 'w-32 mr-2 mb-2 bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full'
    b = jp.Button(text=f'Reset zoom', a=wp, classes=button_classes, click=button_click)

    # Need the folowing if using cyto.run_method_get_output:
    wp.on('result_ready', wp.cyto.handle_page_event)

    return wp

jp.justpy(cyto_test)

Pass in parameters by structuring the argument of the method as a string. e.g.

async def button_click(self, msg):
    cy = msg.page.cyto
    ws = msg.websocket
    await cy.run_method('zoom(2)', ws)
    await cy.run_method("layout({'name':'random'}).run()", ws)
    x = 100
    y = 10
    await cy.run_method(f'pan({{x:{x}, y:{y}}})', ws)

Use run_method_get_output to obtain the output. Stacking function calls and using selectors works. Remember to bind ‘result_ready’ to cyto.handle_page_event.

e.g.

async def button_click(self, msg):
    cy = msg.page.cyto
    ws = msg.websocket
    a=await cy.run_method_get_output('json()', ws)
    a=await cy.run_method_get_output('getElementById("a").position()', ws)
    a=await cy.run_method_get_output('$("#a").position()', ws)

Events

To bind to Cytoscape events, first list the event in the attribute allowed_events then use on(). e.g.

async def pos_changed(self, msg):
    target = msg.target_id
    pos = await msg.page.cyto.run_method_get_output(f'getElementById("{target}").position()', msg.websocket)
    print(f'Node "{target}" moved to {pos}')

def cyto_test():
    wp = jp.WebPage()
    wp.head_html = '''
    <script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.21.1/cytoscape.min.js"></script>
    '''
    wp.cyto = Cytoscape(a=wp,
                     style = 'background-color: #fefefe; border: 1px solid; width: 400px; height: 400px;',
                     classes='m-2',
                     elements = elements,
                     graphstyle = graphstyle,
                     layout = layout,
                     allowed_events = ['free'],
                     )

    wp.cyto.on('free', pos_changed)
    wp.on('result_ready', wp.cyto.handle_page_event)
    return wp

jp.justpy(cyto_test)

:Node “a” moved to {‘x’: 131.17751479289942, ‘y’: 123.07396449704142}

Plugins

This is a bit hackish but possible.

When the Cytoscape object is instantiated you can pass in a list of strings in the attribute plugins. The strings should be javascript code to register and configure plugins (they get passed to eval()). Function calls and events for the plugins are available on the python cyto object as usual. The js cytograph instance is available in the variable cyto if you need to bind callbacks.

e.g. after installing ctxmenu and compound=drag-and-drop to the static/ dir,

ctxmenuconfig = """
cyto.cxtmenu({
    selector: 'core',

    commands: [
        { content: 'Fit',
        select: function(){
            cyto.fit();
        }},

        { content: 'bg',
        select: function(){
            console.log( 'bg' );
            const edata = {
                'event_type': 'ctxmenu',
                'data': 'bg',
                'id': props.jp_props.id,
                'page_id': page_id,
                'websocket_id': websocket_id
            };
            send_to_server(edata, 'event');
        }}
]});
"""

def echo(*args):
    print(args)

def cyto_test():
    wp = jp.WebPage()
    wp.head_html = '''
    <script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.21.1/cytoscape.min.js"></script>
    <script src="/static/cytoscape-cxtmenu.js"></script>
    <script src="/static/cytoscape-compound-drag-and-drop.js"></script>
    '''
    wp.cyto = Cytoscape(a=wp,
                     style = 'background-color: #fefefe; border: 1px solid; width: 400px; height: 400px;',
                     classes='m-2',
                     elements = elements,
                     graphstyle = graphstyle,
                     layout = layout,
                     allowed_events = ['ctxmenu','free','tap'],
                     plugins = [ctxmenuconfig, "cyto.compoundDragAndDrop({})"],
                     )

    wp.cyto.on('ctxmenu', echo)
    return wp

jp.justpy(cyto_test)

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published