Use Case for "Automating the PathLinker App for Cytoscape" - F1000, 2018

Requirments

  • Java 8
  • Cytoscape 3.6.0+
  • cyREST 3.6.0+
  • PathLinker App 1.4.1+
  • py2cytoscape 0.4.2+

In [29]:
# necessary libraries and dependencies
import sys
from py2cytoscape.data.cyrest_client import CyRestClient
from py2cytoscape.data.style import StyleUtil

import networkx as nx
import pandas as pd
import json
import requests

print("python version: " + sys.version)
# The py2cytoscape module doesn't have a version. I installed it 2018-04-13
#print("py2cytoscape version: " + py2cytoscape.__version__)
print("networkx version: " + nx.__version__)
print("pandas version: " + pd.__version__)
print("requests version: " + requests.__version__)


python version: 2.7.12 (default, Dec  4 2017, 14:50:18) 
[GCC 5.4.0 20160609]
networkx version: 2.1
pandas version: 0.22.0
requests version: 2.18.4

In [34]:
# !!!!!!!!!!!!!!!!! Step 0: Start Cytoscape 3.6 with cyREST App !!!!!!!!!!!!!!!!!!!!!!!!!!
# Cytoscape must be running to use the automation features

# Step 1: create an instance of cyRest client
cy = CyRestClient()

# Reset the session
#cy.session.delete()

Create network using networkx

This example uses the small and simple network found here: network-example-undirected.txt.


In [60]:
# Step 2: Import/Create the network that PathLinker will run on
network_file = 'network-example-undirected.txt'

# create a new network by importing the data from a sample using pandas
df = pd.read_csv(network_file, sep='\t', lineterminator='\n')

# and create the networkx Graph from the pandas dataframe
G = nx.from_pandas_edgelist(df, "source", "target")
    
# create the CyNetwork object from the networkx in CytoScape
cy_network = cy.network.create_from_networkx(G, name = 'network-example-undirected', collection = 'F1000 PathLinker Use Case')

# obtain the CyNetwork object SUID
cy_network_suid = cy_network.get_id()

In [59]:
# give the network some style and a layout
my_style = cy.style.create('defaut')

# copied from here: https://github.com/cytoscape/cytoscape-automation/blob/master/for-scripters/Python/basic-fundamentals.ipynb
basic_settings = {    
    'NODE_FILL_COLOR': '#6AACB8',
    'NODE_SIZE': 55,
    'NODE_BORDER_WIDTH': 0,
    'NODE_LABEL_COLOR': '#555555',
    
    'EDGE_WIDTH': 2,
    'EDGE_TRANSPARENCY': 100,
    'EDGE_STROKE_UNSELECTED_PAINT': '#333333',
    
    'NETWORK_BACKGROUND_PAINT': '#FFFFEA'
}

my_style.update_defaults(basic_settings)

# Create some mappings
my_style.create_passthrough_mapping(column='name', vp='NODE_LABEL', col_type='String')

cy.layout.apply(name="force-directed", network=cy_network)
cy.style.apply(my_style, cy_network)
#cy.layout.fit(network=cy_network)

The network shown below will be generated in Cytoscape with the above code.

Run PathLinker using the API function

Run PathLinker

The function takes user sources, targets, and a set of parameters, and computes the k shortest paths. The function returns the paths in JSON format. Based on the user input, the function could generate a subnetwork (and view) containing those paths, and returns the computed paths and subnetwork/view SUIDs.

Additional description of the parameters are available in the PathLinker app documentation.


In [37]:
# Step 3: Construct input data to pass to PathLinker API function

# construct PathLinker input data for API request
# For a description of all of the parameters, please see below
params = {
    'sources': 'a',
    'targets': 'e h',
    'k': 2,  # the number of shortest path to compute
    'treatNetworkAsUndirected': True,  # Our graph is undirected, so use this option
    'includeTiedPaths': True,  # This option is not necessary. I'm including it here just to show what it does
}

# construct REST API request url
url = "http://localhost:1234/pathlinker/v1/" + str(cy_network_suid) + "/run"
# to just run on the network currently in view on cytoscape, use the following:
# url = "http://localhost:1234/pathlinker/v1/currentView/run"

headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}

# perform the REST API call
result_json = requests.request("POST", 
                          url,
                          data = json.dumps(params),
                          params = None,
                          headers = headers)

In [ ]:
# ------------ Description of all parameters ------------------
# the node names for the sources and targets are space separated 
# and must match the "name" column in the Node Table in Cytoscape
params["sources"] = "a"
params["targets"] = "e h"

# the number of shortest path to compute, must be greater than 0
# Default: 50
params["k"] = 2

# Edge weight type, must be one of the three: [UNWEIGHTED, ADDITIVE, PROBABILITIES]
params["edgeWeightType"] = "UNWEIGHTED" 

# Edge penalty. Not needed for UNWEIGHTED 
# Must be 0 or greater for ADDITIVE, and 1 or greater for PROBABILITIES 
params["edgePenalty"] = 0

# The column name in the Edge Table in Cytoscape containing edge weight property, 
# column type must be numerical type 
params["edgeWeightColumnName"] = "weight"

# The option to ignore directionality of edges when computing paths
# Default: False
params["treatNetworkAsUndirected"] = True

# Allow source/target nodes to appear as intermediate nodes in computed paths
# Default: False
params["allowSourcesTargetsInPaths"] = False

# Include more than k paths if the path length/score is equal to kth path length/score
# Default: False
params["includeTiedPaths"] = False

# Option to disable the generation of the subnetwork/view, path rank column, and result panel
# and only return the path result in JSON format
# Default: False
params["skipSubnetworkGeneration"] = False

Output

The app will generate the following (shown below):

  • a subnetwork containing the paths (with the hierarchical layout applied)
  • a path rank column in the Edge Table (shows for each edge, the rank of the first path in which it appears)
  • a Result Panel within Cytoscape.

The API will return:

  • the computed paths
  • the SUIDs of the generated subnetwork and subnetwork view
  • the path rank column name in JSON format.


In [62]:
# Step 4: Store result, parse, and print
results = json.loads(result_json.content)

print("Output:\n")

# access the suid, references, and path rank column name
subnetwork_suid = results["subnetworkSUID"]
subnetwork_view_suid = results["subnetworkViewSUID"]
# The path rank column shows for each edge, the rank of the first path in which it appears
path_rank_column_name = results["pathRankColumnName"]
    
print("subnetwork SUID:       %s" % (subnetwork_suid))
print("subnetwork view SUID:  %s" % (subnetwork_view_suid))
print("Path rank column name: %s" % (path_rank_column_name))
print("")


# access the paths generated by PathLinker
paths = results["paths"]

# print the paths found
for path in paths:
    print("path rank:  %d" % (path['rank']))
    print("path score: %s" % (str(path['score'])))
    print("path:       %s" % ("|".join(path['nodeList'])))


Output:

subnetwork SUID:       157
subnetwork view SUID:  167
Path rank column name: path rank 1

path rank:  1
path score: 2.0
path:       a|f|e
path rank:  2
path score: 3.0
path:       a|f|g|h
path rank:  3
path score: 3.0
path:       a|f|i|e

In [ ]:
# write them to a file
paths_file = "use-case-images/paths.txt"
print("Writing paths to %s" % (paths_file))
with open(paths_file, 'w') as out:
    out.write("path rank\tpath score\tpath\n")
    for path in paths:
        out.write('%d\t%s\t%s\n' % (path['rank'], str(path['score']), "|".join(path['nodeList'])))

In [54]:
# access network and network view references
subnetwork = cy.network.create(suid=subnetwork_suid)
#subnetwork_view = subnetwork.get_first_view()

# TODO copy the layout of the original graph to this graph to better visualize the results.
# The copycat layout doesn't seem to be working
# for now, just apply the cose layout to get a little better layout (see image below)
cy.layout.apply(name="cose", network=subnetwork)

The subnetwork with "cose" layout will look something like this:

Visualization using cytoscape.js and py2cytoscape


In [21]:
# *** Currently the function does not work therefore is commented out. ***
# import py2cytoscape.cytoscapejs as renderer

# # visualize the subnetwork view using CytoScape.js
# renderer.render(subnetwork_view, 'Directed', background='radial-gradient(#FFFFFF 15%, #DDDDDD 105%)')

View the subnetwork and store the image


In [ ]:
# png
subnetwork_image_png = subnetwork.get_png()
subnetwork_image_file = 'use-case-images/subnetwork-image.png'
print("Writing PNG to %s" % (subnetwork_image_file))
with open(subnetwork_image_file, 'wb') as f:
    f.write(subnetwork_image_png)

from IPython.display import Image
Image(subnetwork_image_png)

# # pdf
# subnetwork_image_pdf = subnetwork.get_pdf()
# subnetwork_image_file = subnetwork_image_file.replace('.png', '.pdf')
# print("Writing PDF to %s" % (subnetwork_image_file))
# with open(subnetwork_image_file, 'wb') as f:
#     f.write(subnetwork_image_pdf)
# # display the pdf in frame
# from IPython.display import IFrame
# IFrame('use_case_images/subnetwork_image.pdf', width=600, height=300)

# # svg
# subnetwork_image_svg = subnetwork.get_svg()

# from IPython.display import SVG
# SVG(subnetwork_image_svg)