This is an introduction to cyREST and its API. You will learn how to access Cytoscape via RESTful API.
In [1]:
import sys
print ('My Python Version = ' + sys.version)
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 cyREST is 1234. To change this, you need set a global Cytoscape property from:
and add a new property resr.port.
Before running following cells, install dependent Python packages with
pip install -U requests
In [2]:
# HTTP Client for Python
import requests
# Standard JSON library
import json
# Basic Setup
PORT_NUMBER = 1234
# Specify your machine's URL (The IP address of the machine running Cytoscape and cyREST) if you use
# Docker or remote server for this notebook.
#IP = '192.168.1.1'
# If you are running both Notebook server and Cytoscape on a same machine, just use localhost
IP = 'localhost'
BASE = 'http://' + IP + ':' + 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 [3]:
# Get server status
res = requests.get(BASE)
In [4]:
status_object = res.json();
print(json.dumps(status_object, indent=4))
JSON library in Python converts JSON string into simple Python object.
In [5]:
print(status_object['apiVersion'])
print(status_object['memoryStatus']['usedMemory'])
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 [6]:
# Small utility function to create networks from list of URLs
def create_from_list(network_list):
server_res = requests.post(BASE + 'networks?source=url&collection=Yeast Collection', data=json.dumps(network_list), headers=HEADERS)
return server_res.json()
# This is not necessary if you directly specify absolute file path like "/Users/foo/bar/sample_data/yeast.json"
import os
filepath = os.path.abspath('sample_data/yeast.json')
import platform
if platform.system() != 'Windows':
filepath = 'file://' + filepath
print('Target Local File = ' + filepath)
In [7]:
# Array of data source.
network_files = [
# Local file in this example data directory
# 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 [8]:
# 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 [9]:
mixed = [
#'file://' + filepath,
'http://chianti.ucsd.edu/cytoscape-data/galFiltered.sif',
# Uncomment the line below if you have fast internet connection
#'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 [10]:
# 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':[]
}
}
res = requests.post(BASE + 'networks?collection=My%20Collection', data=json.dumps(empty_network), headers=HEADERS)
net_suid = res.json()['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 [11]:
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 = list(map(build_node, seq_letters))
build_edge = lambda x: {'data': { 'source': x, 'target': 'a' }}
rand_edges = list(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))
res = requests.post(BASE + 'networks?collection=My%20Collection', data=json.dumps(small_network), headers=HEADERS)
res_dict = res.json()
new_suid = res_dict['networkSUID']
# Apply layout
requests.get(BASE + 'apply/layouts/force-directed/' + str(new_suid))
Out[11]:
In [12]:
from IPython.display import Image
Image(url=BASE+'networks/' + str(new_suid) + '/views/first.png', embed=True)
Out[12]:
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 [13]:
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'
el = list(map(el_builder, numbers))
edgelist = ''.join(el)
res = requests.post(BASE + 'networks?format=edgelist&collection=Ring', data=edgelist, headers=HEADERS)
res_dict = res.json()
circle_suid = res_dict['networkSUID']
requests.get(BASE + 'apply/layouts/circular/' + str(circle_suid))
Image(url=BASE+'networks/' + str(circle_suid) + '/views/first.png', embed=True)
Out[13]:
In [14]:
from IPython.core.display import SVG
svg_url = BASE+'networks/' + str(circle_suid) + '/views/first.svg'
print(svg_url)
SVG(url=svg_url)
Out[14]:
In [15]:
# Generate PDF from the network and save it in current directory:
pdf_url = BASE+'networks/' + str(circle_suid) + '/views/first.pdf'
print(pdf_url)
if sys.version_info.major == 3:
# Python 3.4.x
import urllib.request
res = urllib.request.urlretrieve(pdf_url, "network.pdf")
else:
# Python 2.7.x
import urllib
res = urllib.urlretrieve(pdf_url, "network.pdf")
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.