This is an introduction to Cytoscape via RESTful API. You will learn how to access Cytoscape via RESTful API.
Please send them to our mailing list
In this tutorial, we will use several popular Python libraries to make this workflow more realistic.
Since you need to access Cytoscape via RESTful API, HTTP client library is the most important tool you need to understand. In this example, we use Requests library to simplify API call code.
Data will be exchanged as JSON between Cytoscape and Python code. Python has built-in support for JSON and we will use it in this workflow.
At this point, there is only one option for the cy-rest module: port number.
We assume you are running Cytoscape desktop application and IPython Notebook server on a same machine. To access Cytoscape REST API, use the following URL:
http://localhost:PORT_NUMBER/v1/
where v1 is the current version number of API. Once the final release is ready, we guarantee compatibility of your scripts as long as major version number is the same.
Of course, you can run Cytoscape and IPython server on different machines. In that case, you need to change the URL to the machine running Cytoscape desktop. Also, you need to open the port.
By default, port number used by cy-rest module is 1234. To change this, you need set a global Cytoscape property from Edit-->Preserences-->Properties... and add a new property port.number.
In [1]:
import requests
import json
# Basic Setup
PORT_NUMBER = 1234
BASE = 'http://localhost:' + str(PORT_NUMBER) + '/v1/'
# Header for posting data to the server as JSON
HEADERS = {'Content-Type': 'application/json'}
HTTP Verb | Description |
---|---|
GET | Retrieving resources (in most cases, it is Cytoscape data objects, such as networks or tables) |
POST | Creating resources |
PUT | Changing/replacing resources or collections |
DELETE | Deleting resources |
First, send a simple request and check the server status.
In [6]:
# Get server status
res = requests.get(BASE)
In [13]:
status_object = json.loads(res.content);
server_name = status_object['server']
print('Your server is ' + server_name)
You can convert it again into human-readable text:
In [14]:
print(json.dumps(status_object, indent=4))
If you are comfortable with this data type conversion, you are ready to go!
There are many ways to load networks into Cytoscape from REST API:
Let's start from a simple file loading examples. The POST method is used to create new Cytoscape objects. For example,
POST http://localhost:1234/v1/networks
means create new network(s) by specified method. If you want to create networks from files on your machine or remote servers, all you need to do is create a list of file locations and post it to Cytoscape.
In [25]:
# Small utility function to create networks from list of URLs
def create_from_list(network_list):
server_res = requests.post(BASE + 'networks?source=url', data=json.dumps(network_list), headers=HEADERS)
return json.loads(server_res.content)
# This is not necessary if you directly specify absolute file path like "/Users/foo/bar/sample_data/yeast_network.json"
import os
filepath = os.path.abspath('sample_data/yeast_network.json')
# Array of data source.
network_files = [
# Local file in this example data directory
'file://' + filepath,
# SIF file on a web server
'http://chianti.ucsd.edu/cytoscape-data/galFiltered.sif'
# And of course, you can add as many files as you need...
]
# Create!
print(json.dumps(create_from_list(network_files), indent=4))
There are many public network data services. If the service supports Cytoscape-readable file formats, you can specify the query URL as a network location. For example, the following URL calls PSICQUIC web service and returns the search result in PSIMI 2.5 XML format. Since Cytoscape supports PSIMI2.5 files by default, this automatically creates a network from the response from the web service.
In [26]:
# This may take a while because Cytoscape fetch the data from a server in UK...
queries = [ 'http://www.ebi.ac.uk/Tools/webservices/psicquic/intact/webservices/current/search/query/brca1?format=xml25' ]
print(json.dumps(create_from_list(queries), indent=4))
And of course, you can mix local files, URLs, and list of web service queries in a same list:
In [29]:
mixed = [
'file://' + filepath,
'http://chianti.ucsd.edu/cytoscape-data/galFiltered.sif',
'http://www.ebi.ac.uk/Tools/webservices/psicquic/intact/webservices/current/search/query/brca2?format=xml25'
]
print(json.dumps(create_from_list(mixed), indent=4))
And this is the most powerful feature in Cytoscape REST API. You can easily convert Python objects into Cytoscape networks, tables, or Visual Styles
Cytoscape REST API sends and receives data as JSON. For networks, it uses Cytoscape.js style JSON (support for more file formats are comming!). You can programmatically generates networks by converting Python dictionary into JSON.
Let's start with the simplest network JSON:
In [101]:
# Start from a clean slate: remove all networks from current session
requests.delete(BASE + 'networks')
# Manually generates JSON as dictionary
empty_network = {
'data': {
'name': 'I\'m empty!'
},
'elements': {
'nodes':[],
'edges':[]
}
}
res3 = requests.post(BASE + 'networks?collection=My%20Collection', data=json.dumps(empty_network), headers=HEADERS)
res3_dict = json.loads(res3.content)
net_suid = res3_dict['networkSUID']
print('Empty network has SUID ' + str(net_suid))
Since it's a simple Python dictionary, it is easy to add data to the network. Let's add some nodes and edges:
In [59]:
import copy
# Create a copy of the empty network object
small_network = copy.deepcopy(empty_network)
# Sequence of letters (a-z)
seq_letters = list(map(chr, range(ord('a'), ord('z')+1)))
# Build nodes and edges (in functional way)
build_node = lambda x: {'data': { 'id': x }}
abc_nodes = map(build_node, seq_letters)
build_edge = lambda x: {'data': { 'source': x, 'target': 'a' }}
rand_edges = map(build_edge, seq_letters)
small_network['elements']['nodes'] = abc_nodes
small_network['elements']['edges'] = rand_edges
small_network['data']['name'] = 'A is the hub.'
# Uncomment this if you want to see the actual JSON object
# print(json.dumps(small_network, indent=4))
res3 = requests.post(BASE + 'networks?collection=My%20Collection2', data=json.dumps(small_network), headers=HEADERS)
res3_dict = json.loads(res3.content)
new_suid = res3_dict['networkSUID']
# Apply layout
requests.get(BASE + 'apply/layouts/force-directed/' + str(new_suid))
Out[59]:
It's simple, isn't it?
Edgelist is a minimalistic data format for networks and it is widely used in popular libraries including NetworkX and igraph. Preparing edgelist in Python is straightforward. You just need to prepare a list of edges as string like:
a b
b c
a c
In Python, there are many ways to generate string like this. Here is a naive approach:
In [112]:
numbers = range(1,101)
el_builder = lambda x: str(x) + '\t' + str(1) if x is 100 else str(x) + '\t' + str(x+1) + '\n'
res3 = requests.post(BASE + 'networks?format=edgelist&collection=Ring', data=reduce(lambda x, y: x + y, map(el_builder, numbers)), headers=HEADERS)
res3_dict = json.loads(res3.content)
circle_suid = res3_dict['networkSUID']
requests.get(BASE + 'apply/layouts/circular/' + str(circle_suid))
Out[112]:
In this section, we've learned how to generate networks programmatically from Python. But for real world problems, it is not a good idea to use low level Python objects to generate networks because there are lots of cool libraries such as NetworkX or igraph. In the next session, let's use those to analyze real network data and visualize them in Cytoscape.