Introduction to py2cytoscape: Pythonista-friendly wrapper for cyREST

For

by Keiichiro Ono - University of California, San Diego Trey Ideker Lab

Requirments

  • Java 8
  • Cytoscape 3.2.1+
  • cyREST 1.1.0+
  • py2cytoscape 0.4.2+

Q. What is py2cytoscape?

A. A Python package to drive Cytoscape in pythonic way

In a Nutshell...

In [1]:
!pip install ../.
Processing /Users/kono/git/py2cytoscape
  Requirement already satisfied (use --upgrade to upgrade): py2cytoscape==0.4.3 from file:///Users/kono/git/py2cytoscape in /Users/kono/anaconda/lib/python3.4/site-packages
Requirement already satisfied (use --upgrade to upgrade): pandas in /Users/kono/anaconda/lib/python3.4/site-packages (from py2cytoscape==0.4.3)
Requirement already satisfied (use --upgrade to upgrade): networkx in /Users/kono/anaconda/lib/python3.4/site-packages (from py2cytoscape==0.4.3)
Requirement already satisfied (use --upgrade to upgrade): requests in /Users/kono/anaconda/lib/python3.4/site-packages (from py2cytoscape==0.4.3)
Requirement already satisfied (use --upgrade to upgrade): python-igraph in /Users/kono/anaconda/lib/python3.4/site-packages (from py2cytoscape==0.4.3)
Requirement already satisfied (use --upgrade to upgrade): pyparsing in /Users/kono/anaconda/lib/python3.4/site-packages (from py2cytoscape==0.4.3)
Requirement already satisfied (use --upgrade to upgrade): scipy in /Users/kono/anaconda/lib/python3.4/site-packages (from py2cytoscape==0.4.3)
Requirement already satisfied (use --upgrade to upgrade): python-dateutil>=2 in /Users/kono/anaconda/lib/python3.4/site-packages (from pandas->py2cytoscape==0.4.3)
Requirement already satisfied (use --upgrade to upgrade): pytz>=2011k in /Users/kono/anaconda/lib/python3.4/site-packages (from pandas->py2cytoscape==0.4.3)
Requirement already satisfied (use --upgrade to upgrade): numpy>=1.7.0 in /Users/kono/anaconda/lib/python3.4/site-packages (from pandas->py2cytoscape==0.4.3)
Requirement already satisfied (use --upgrade to upgrade): six>=1.5 in /Users/kono/anaconda/lib/python3.4/site-packages (from python-dateutil>=2->pandas->py2cytoscape==0.4.3)
In [2]:
from py2cytoscape.data.cynetwork import CyNetwork
from py2cytoscape.data.cyrest_client import CyRestClient
from py2cytoscape.data.style import StyleUtil
import py2cytoscape.util.cytoscapejs as cyjs
import py2cytoscape.cytoscapejs as renderer

import networkx as nx
import pandas as pd
import json
In [3]:
# !!!!!!!!!!!!!!!!! Step 0: Start Cytoscape 3 with cyREST App !!!!!!!!!!!!!!!!!!!!!!!!!!

# Step 1: Create py2cytoscape client
cy = CyRestClient()

# Reset
cy.session.delete()

# Step 2: Load network from somewhere
yeast_net = cy.network.create_from('../tests/data/galFiltered.json')

# Step 3: Load table as pandas' DataFrame
table_data = pd.read_csv('sample_data_table.csv', index_col=0)
table_data.head()
Out[3]:
alias annotation.DB_Object_Name annotation.GO BIOLOGICAL_PROCESS annotation.GO CELLULAR_COMPONENT annotation.GO MOLECULAR_FUNCTION label kegg uniprot sgd entrez
YAL003W translation elongation factor EF-1beta, EF-1 b... EF-1 beta, translation elongation factor EF-1beta translational elongation eukaryotic translation elongation factor 1 com... translation elongation factor activity EF1B sce:YAL003W EF1B_YEAST S000000003 851260
YAL030W S000000028, SNC1 NaN Golgi to plasma membrane transport, endocytosi... Golgi trans face, SNARE complex, endosome, tra... v-SNARE activity SNC1 sce:YAL030W SNC1_YEAST S000000028 851203
YAL038W CDC19, PYK1, S000000036, pyruvate kinase pyruvate kinase glycolysis, pyruvate metabolic process cytosol pyruvate kinase activity KPYK1 sce:YAL038W KPYK1_YEAST S000000036 851193
YAL040C CLN3, DAF1, FUN10, G1 cyclin, S000000038, WHI1 G1 cyclin G1/S transition of mitotic cell cycle, regulat... nucleus cyclin-dependent protein kinase regulator acti... CG13 sce:YAL040C CG13_YEAST S000000038 851191
YAR007C heterotrimeric RPA (RF-A) single-stranded DNA ... RF-A, heterotrimeric RPA (RF-A) single-strande... DNA recombination, DNA replication, synthesis ... DNA replication factor A complex, chromosome, ... damaged DNA binding, single-stranded DNA binding RFA1 sce:YAR007C RFA1_YEAST S000000065 851266
In [4]:
# Step 4: Merge them in Cytoscape
yeast_net.update_node_table(df=table_data, network_key_col='name')

# Step 5: Apply layout
cy.layout.apply(name='force-directed', network=yeast_net)

# Step 6: Create Visual Style as code (or by hand if you prefer)
my_yeast_style = cy.style.create('GAL Style')


basic_settings = {
    
    # You can set default values as key-value pairs.
    
    '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_yeast_style.update_defaults(basic_settings)

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

degrees = yeast_net.get_node_column('Degree') 
color_gradient = StyleUtil.create_2_color_gradient(min=degrees.min(), max=degrees.max(), colors=('white', '#6AACB8'))
degree_to_size = StyleUtil.create_slope(min=degrees.min(), max=degrees.max(), values=(10, 100))
my_yeast_style.create_continuous_mapping(column='Degree', vp='NODE_FILL_COLOR', col_type='Integer', points=color_gradient)
my_yeast_style.create_continuous_mapping(column='Degree', vp='NODE_SIZE', col_type='Integer', points=degree_to_size)
my_yeast_style.create_continuous_mapping(column='Degree', vp='NODE_LABEL_FONT_SIZE', col_type='Integer', points=degree_to_size)

cy.style.apply(my_yeast_style, yeast_net)

# Step 7: (Optional) Embed as interactive Cytoscape.js widget
yeast_net_view = yeast_net.get_first_view()
style_for_widget = cy.style.get(my_yeast_style.get_name(), data_format='cytoscapejs')
renderer.render(yeast_net_view, style=style_for_widget['style'], background='radial-gradient(#FFFFFF 15%, #DDDDDD 105%)')

Long Description

From version 0.4.0, py2cytoscape has wrapper modules for cyREST RESTful API. This means you can access Cytoscape features in more Pythonic way instead of calling raw REST API via HTTP.

Features

Pandas for basic data exchange

Since pandas is a standard library for data mangling/analysis in Python, this new version uses its DataFrame as its basic data object.

Embedded Cytoscaep.js Widget

You can use Cytoscape.js widget to embed your final result as a part of your notebook.

Simpler Code to access Cytoscape

cyREST provides language-agnostic RESTful API, but you need to use a lot of template code to access raw API. Here is an example. Both of the following do the same task, which is creating an empty network in Cytoscape. You will notice it is significantly simpler if you use py2cytoscape wrapper API.

Raw cyREST

In [5]:
# HTTP Client for Python
import requests

# Standard JSON library
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'}

# Define dictionary of empty network
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)
new_network_id = res.json()['networkSUID']
print('New network created with raw REST API.  Its SUID is ' + str(new_network_id))
New network created with raw REST API.  Its SUID is 239076

With py2cytoscape

In [6]:
network = cy.network.create(name='My Network', collection='My network collection')
print('New network created with py2cytoscape.  Its SUID is ' + str(network.get_id()))
New network created with py2cytoscape.  Its SUID is 239104

Status

As of 6/4/2015, this is still in alpha status and feature requests are always welcome. If youi have questions or feature requests, please send them to our Google Groups:

Quick Tour of py2cytoscape Features


Create a client object to connect to Cytoscape

In [7]:
# Create an instance of cyREST client.  Default IP is 'localhost', and port number is 1234.
# cy = CyRestClient() - This default constructor creates connection to http://localhost:1234/v1
cy = CyRestClient(ip='127.0.0.1', port=1234)

# Cleanup: Delete all existing networks and tables in current Cytoscape session
cy.session.delete()

Creating empty networks

In [8]:
# Empty network
empty1 = cy.network.create()

# With name
empty2 = cy.network.create(name='Created in Jupyter Notebook')

# With name and collection name
empty3 = cy.network.create(name='Also created in Jupyter', collection='New network collection')

Load networks from files, URLs or web services

In [9]:
# Load a single local file
net_from_local2 = cy.network.create_from('../tests/data/galFiltered.json')
net_from_local1 = cy.network.create_from('sample_yeast_network.xgmml', collection='My Collection')
net_from_local2 = cy.network.create_from('../tests/data/galFiltered.gml', collection='My Collection')

# Load from multiple locations
network_locations = [
    'sample_yeast_network.xgmml', # Local file
    'http://chianti.ucsd.edu/cytoscape-data/galFiltered.sif', # Static file on a web server
    'http://www.ebi.ac.uk/Tools/webservices/psicquic/intact/webservices/current/search/query/brca1?format=xml25' # or a web service
]

# This requrns Series
networks = cy.network.create_from(network_locations)
pd.DataFrame(networks, columns=['CyNetwork'])
Out[9]:
CyNetwork
file:////Users/kono/git/py2cytoscape/examples/sample_yeast_network.xgmml <py2cytoscape.data.cynetwork.CyNetwork object ...
http://chianti.ucsd.edu/cytoscape-data/galFiltered.sif <py2cytoscape.data.cynetwork.CyNetwork object ...
http://www.ebi.ac.uk/Tools/webservices/psicquic/intact/webservices/current/search/query/brca1?format=xml25 <py2cytoscape.data.cynetwork.CyNetwork object ...

Create networks from various types of data

Currently, py2cytoscape accepts the following data as input:

  • Cytoscape.js
  • NetworkX
  • Pandas DataFrame
  • igraph (TBD)
  • Numpy adjacency matrix (binary or weighted) (TBD)
  • GraphX (TBD)
In [10]:
# Cytoscape.js JSON
n1 = cy.network.create(data=cyjs.get_empty_network(), name='Created from Cytoscape.js JSON')
In [11]:
# Pandas DataFrame

# Example 1: From a simple text table
df_from_sif = pd.read_csv('../tests/data/galFiltered.sif', names=['source', 'interaction', 'target'], sep=' ')
df_from_sif.head()
Out[11]:
source interaction target
0 YKR026C pp YGL122C
1 YGR218W pp YGL097W
2 YGL097W pp YOR204W
3 YLR249W pp YPR080W
4 YLR249W pp YBR118W
In [12]:
# By default, it uses 'source' for source node column, 'target' for target node column, and 'interaction' for interaction
yeast1 = cy.network.create_from_dataframe(df_from_sif, name='Yeast network created from pandas DataFrame')

# Example 2: from more complicated table
df_from_mitab = pd.read_csv('intact_pubid_22094256.txt', sep='\t')
df_from_mitab.head()
Out[12]:
#ID(s) interactor A ID(s) interactor B Alt. ID(s) interactor A Alt. ID(s) interactor B Alias(es) interactor A Alias(es) interactor B Interaction detection method(s) Publication 1st author(s) Publication Identifier(s) Taxid interactor A ... Checksum(s) interactor A Checksum(s) interactor B Interaction Checksum(s) Negative Feature(s) interactor A Feature(s) interactor B Stoichiometry(s) interactor A Stoichiometry(s) interactor B Identification method participant A Identification method participant B
0 uniprotkb:Q8IZC7 uniprotkb:P11802 intact:EBI-5278328|uniprotkb:C9JU83|uniprotkb:... intact:EBI-295644|uniprotkb:B2R9A0|uniprotkb:B... psi-mi:zn101_human(display_long)|uniprotkb:ZNF... psi-mi:cdk4_human(display_long)|uniprotkb:CDK4... psi-mi:"MI:0424"(protein kinase assay) Anders et al. (2011) pubmed:22094256|imex:IM-16628 taxid:9606(human)|taxid:9606(Homo sapiens) ... rogid:mZLXs/PbWbfgLzkjwZfoE2c6jy09606 rogid:pxIzF9EkX+gMz7zj/TDiytYtsOc9606 intact-crc:0486DE729E5A8158|rigid:3gdrHm0coV8S... False glutathione s tranferase tag:?-? sufficient binding region:4-303|glutathione s ... - - psi-mi:"MI:0821"(molecular weight estimation b... psi-mi:"MI:0821"(molecular weight estimation b...
1 uniprotkb:P01106 uniprotkb:Q00534 intact:EBI-447544|intact:EBI-1058440|uniprotkb... intact:EBI-295663|uniprotkb:A4D1G0 psi-mi:myc_human(display_long)|uniprotkb:BHLHE... psi-mi:cdk6_human(display_long)|uniprotkb:CDK6... psi-mi:"MI:0424"(protein kinase assay) Anders et al. (2011) pubmed:22094256|imex:IM-16628 taxid:9606(human)|taxid:9606(Homo sapiens) ... rogid:CCk+p9FN7JV6cTmJDlin2hRp1tg9606 rogid:IlAJCZ9bvB5RaBdS1rlPnqDL9xg9606 intact-crc:20A3DCC8419B269E|rigid:bfSR2lJKa/lY... False glutathione s tranferase tag:?-? his tag:n-n - - psi-mi:"MI:0821"(molecular weight estimation b... psi-mi:"MI:0821"(molecular weight estimation b...
2 uniprotkb:Q00534 uniprotkb:P28698 intact:EBI-295663|uniprotkb:A4D1G0 intact:EBI-5278283|uniprotkb:M0QXU0|uniprotkb:... psi-mi:cdk6_human(display_long)|uniprotkb:CDK6... psi-mi:mzf1_human(display_long)|uniprotkb:MZF1... psi-mi:"MI:0424"(protein kinase assay) Anders et al. (2011) pubmed:22094256|imex:IM-16628 taxid:9606(human)|taxid:9606(Homo sapiens) ... rogid:IlAJCZ9bvB5RaBdS1rlPnqDL9xg9606 rogid:1rq+ga/Uew705r63KlORpqBObbw9606 intact-crc:578214FA683591D0|rigid:8AADqx3NNAXF... False his tag:n-n glutathione s tranferase tag:?-? - - psi-mi:"MI:0821"(molecular weight estimation b... psi-mi:"MI:0821"(molecular weight estimation b...
3 uniprotkb:P11802 uniprotkb:Q9H165 intact:EBI-295644|uniprotkb:B2R9A0|uniprotkb:B... intact:EBI-765567|uniprotkb:Q86W14|uniprotkb:Q... psi-mi:cdk4_human(display_long)|uniprotkb:CDK4... psi-mi:bc11a_human(display_long)|uniprotkb:B-c... psi-mi:"MI:0424"(protein kinase assay) Anders et al. (2011) pubmed:22094256|imex:IM-16628 taxid:9606(human)|taxid:9606(Homo sapiens) ... rogid:pxIzF9EkX+gMz7zj/TDiytYtsOc9606 rogid:xASsLQWykg/7ZpyjLsQP8GlQ/H09606 intact-crc:F173ABFF34E61592|rigid:5u6F7IwnpEEf... False sufficient binding region:4-303|glutathione s ... glutathione s tranferase tag:?-? - - psi-mi:"MI:0821"(molecular weight estimation b... psi-mi:"MI:0821"(molecular weight estimation b...
4 uniprotkb:Q14980 uniprotkb:Q00534 intact:EBI-521611|uniprotkb:H0YH75|uniprotkb:Q... intact:EBI-295663|uniprotkb:A4D1G0 psi-mi:numa1_human(display_long)|uniprotkb:SP-... psi-mi:cdk6_human(display_long)|uniprotkb:CDK6... psi-mi:"MI:0424"(protein kinase assay) Anders et al. (2011) pubmed:22094256|imex:IM-16628 taxid:9606(human)|taxid:9606(Homo sapiens) ... rogid:goAKbcTz6vzGy3T7RlpGPnTCbdk9606 rogid:IlAJCZ9bvB5RaBdS1rlPnqDL9xg9606 intact-crc:43D7B9AE4E55FAA0|rigid:mLhZxkGnjrpK... False glutathione s tranferase tag:?-? his tag:n-n - - psi-mi:"MI:0821"(molecular weight estimation b... psi-mi:"MI:0821"(molecular weight estimation b...

5 rows × 42 columns

In [13]:
source = df_from_mitab.columns[0]
target = df_from_mitab.columns[1]
interaction = 'Interaction identifier(s)'
title='A Systematic Screen for CDK4/6 Substrates Links FOXM1 Phosphorylation to Senescence Suppression in Cancer Cells.'

human1 = cy.network.create_from_dataframe(df_from_mitab, source_col=source, target_col=target, interaction_col=interaction, name=title)


# Import edge attributes and node attributes at the same time (TBD)
In [14]:
# NetworkX
nx_graph  = nx.scale_free_graph(100)
nx.set_node_attributes(nx_graph, 'Degree', nx.degree(nx_graph))
nx.set_node_attributes(nx_graph, 'Betweenness_Centrality', nx.betweenness_centrality(nx_graph))
scale_free100 = cy.network.create_from_networkx(nx_graph, collection='Generated by NetworkX')

# TODO: igraph
# TODO: Numpy adj. martix
# TODO: GraphX

Get Network from Cytoscape

You can get network data in the following forms:

  • Cytoscape.js
  • NetworkX
  • DataFrame
In [15]:
# As Cytoscape.js (dict)
yeast1_json = yeast1.to_json()

# print(json.dumps(yeast1_json, indent=4))
In [16]:
# As NetworkX graph object
sf100 = scale_free100.to_networkx()

num_nodes = sf100.number_of_nodes()
num_edges = sf100.number_of_edges()

print('Number of Nodes: ' + str(num_nodes))
print('Number of Edges: ' + str(num_edges))
Number of Nodes: 100
Number of Edges: 197
In [17]:
# As a simple, SIF-like DataFrame
yeast1_df = yeast1.to_dataframe()
yeast1_df.head()
Out[17]:
source interaction target
0 YDR277C pp YDL194W
1 YDR277C pp YJR022W
2 YPR145W pp YMR117C
3 YER054C pp YBR045C
4 YER054C pp YER133W

Working with CyNetwork API

CyNetwork class is a simple wrapper for network-related cyREST raw REST API. It does not hold the actual network data. It's a reference to a network in current Cytoscape session. With CyNetwork API, you can access Cytoscape data objects in more Pythonista-friendly way.

In [18]:
network_suid = yeast1.get_id()
print('This object references to Cytoscape network with SUID ' + str(network_suid) + '\n')
print('And its name is: ' + str(yeast1.get_network_value(column='name')) + '\n')

nodes = yeast1.get_nodes()
edges = yeast1.get_edges()

print('* This network has ' + str(len(nodes)) + ' nodes and ' + str(len(edges)) + ' edges\n') 

# Get a row in the node table as pandas Series object
node0 = nodes[0]
row = yeast1.get_node_value(id=node0)
print(row)

# Or, pick one cell in the table
cell = yeast1.get_node_value(id=node0, column='name')
print('\nThis node has name: ' + str(cell))
This object references to Cytoscape network with SUID 246460

And its name is: b'Yeast network created from pandas DataFrame'

* This network has 331 nodes and 362 edges

SUID            246470
id             YKR026C
name           YKR026C
selected         False
shared_name    YKR026C
dtype: object

This node has name: b'YKR026C'

Get references from existing networks

And of course, you can grab references to existing Cytoscape networks:

In [19]:
# Create a new CyNetwork object from existing network
network_ref1 = cy.network.create(suid=yeast1.get_id())

# And they are considered as same objects.
print(network_ref1 == yeast1)
print(network_ref1.get_network_value(column='name'))
True
b'Yeast network created from pandas DataFrame'

Tables as DataFrame

Cytoscape has two main data types: Network and Table. Network is the graph topology, and Tables are properties for those graphs. For simplicity, this library has access to three basic table objects:

  • Node Table
  • Edge Table
  • Network Table

For 99% of your use cases, you can use these three to store properties. Since pandas is extremely useful to handle table data, default data type for tables is DataFrame. However, you can also use other data types including:

  • Cytoscape.js style JSON
  • CSV
  • TSV
  • CX (TBD)
In [20]:
# Get table  from Cytoscape
node_table = scale_free100.get_node_table()
edge_table = scale_free100.get_edge_table()
network_table = scale_free100.get_network_table()
node_table.head()
Out[20]:
shared name name selected id Degree Betweenness_Centrality
SUID
248218 0 0 False 0 63 0.032124
248219 1 1 False 1 94 0.085927
248220 2 2 False 2 24 0.013760
248221 3 3 False 3 7 0.000000
248222 4 4 False 4 13 0.016595
In [21]:
network_table.transpose().head()
Out[21]:
SUID 248208
shared name directed_scale_free_graph(100,alpha=0.41,beta=...
name directed_scale_free_graph(100,alpha=0.41,beta=...
selected True
__Annotations NaN
In [22]:
names = scale_free100.get_node_column('Degree')
print(names.head())

# Node Column information.  "name" is the unique Index
scale_free100.get_node_columns()
0    94
1    63
2     7
3    13
4     7
dtype: float64
Out[22]:
immutable primaryKey type
name
SUID True True Long
shared name True False String
name True False String
selected True False Boolean
id False False String
Degree False False Double
Betweenness_Centrality False False Double

Edit Network Topology

Adding and deleteing nodes/edges

In [23]:
# Add new nodes: Simply send the list of node names.  NAMES SHOULD BE UNIQUE!
new_node_names = ['a', 'b', 'c']
# Return value contains dictionary from name to SUID.
new_nodes = scale_free100.add_nodes(new_node_names)

# Add new edges
# Send a list of tuples:  (source node SUID, target node SUID, interaction type
new_edges = []
new_edges.append((new_nodes['a'], new_nodes['b'], 'type1'))
new_edges.append((new_nodes['a'], new_nodes['c'], 'type2'))
new_edges.append((new_nodes['b'], new_nodes['c'], 'type3'))

new_edge_ids = scale_free100.add_edges(new_edges)
new_edge_ids
Out[23]:
source target
SUID
248820 248814 248815
248821 248814 248816
248822 248815 248816
In [24]:
# Delete node
scale_free100.delete_node(new_nodes['a'])

# Delete edge
scale_free100.delete_edge(new_edge_ids.index[0])

Update Table

Let's do something a bit more realistic. You can update any Tables by using DataFrame objects.

1. ID conversion with external service

Let's use ID Conversion web service by Uniprot to add more information to existing yeast network in current session.

In [25]:
# Small utility function to convert ID sets
import requests

def uniprot_id_mapping_service(query=None, from_id=None, to_id=None):
    # Uniprot ID Mapping service
    url = 'http://www.uniprot.org/mapping/'
    payload = {
        'from': from_id,
        'to': to_id,
        'format':'tab',
        'query': query
    }
    
    res = requests.get(url, params=payload)
    
    df = pd.read_csv(res.url, sep='\t')
    res.close()
    return df
In [26]:
# Get node table from Cytoscape
yeast_node_table = yeast1.get_node_table()

# From KEGG ID to UniprotKB ID
query1 = ' '.join(yeast_node_table['name'].map(lambda gene_id: 'sce:' + gene_id).values)
id_map_kegg2uniprot = uniprot_id_mapping_service(query1, from_id='KEGG_ID', to_id='ID')
id_map_kegg2uniprot.columns = ['kegg', 'uniprot']

# From UniprotKB to SGD
query2 = ' '.join(id_map_kegg2uniprot['uniprot'].values)
id_map_uniprot2sgd = uniprot_id_mapping_service(query2, from_id='ID', to_id='SGD_ID')
id_map_uniprot2sgd.columns = ['uniprot', 'sgd']

# From UniprotKB to Entrez Gene ID
query3 = ' '.join(id_map_kegg2uniprot['uniprot'].values)
id_map_uniprot2ncbi = uniprot_id_mapping_service(query3, from_id='ID', to_id='P_ENTREZGENEID')
id_map_uniprot2ncbi.columns = ['uniprot', 'entrez']

# Merge them
merged = pd.merge(id_map_kegg2uniprot, id_map_uniprot2sgd, on='uniprot')
merged = pd.merge(merged, id_map_uniprot2ncbi, on='uniprot')

# Add key column by removing prefix
merged['name'] = merged['kegg'].map(lambda kegg_id : kegg_id[4:])
merged.head()
Out[26]:
kegg uniprot sgd entrez name
0 sce:YKR026C EI2BA_YEAST S000001734 853896 YKR026C
1 sce:YGL122C NAB2_YEAST S000003090 852755 YGL122C
2 sce:YGR218W XPO1_YEAST S000003450 853133 YGR218W
3 sce:YGL097W RCC1_YEAST S000003065 852782 YGL097W
4 sce:YOR204W DED1_YEAST S000005730 854379 YOR204W
In [27]:
update_url = BASE + 'networks/' + str(yeast1.get_id()) + '/tables/defaultnode'
print(update_url)

ut = {
    'key': 'name',
    'dataKey': 'name',
    'data': [
        {
            'name': 'YBR112C',
            'foo': 'aaaaaaaa'
        }
    ]
}

requests.put(update_url, json=ut, headers=HEADERS)
http://localhost:1234/v1/networks/246460/tables/defaultnode
Out[27]:
<Response [200]>
In [28]:
# Now update existing node table with the data frame above.
yeast1.update_node_table(merged, network_key_col='name', data_key_col='name')

# Check the table is actually updated
yeast1.get_node_table().head()
Out[28]:
shared name name selected id foo kegg entrez uniprot sgd
SUID
246470 YKR026C YKR026C False YKR026C NaN sce:YKR026C 853896 EI2BA_YEAST S000001734
246471 YGL122C YGL122C False YGL122C NaN sce:YGL122C 852755 NAB2_YEAST S000003090
246472 YGR218W YGR218W False YGR218W NaN sce:YGR218W 853133 XPO1_YEAST S000003450
246473 YGL097W YGL097W False YGL097W NaN sce:YGL097W 852782 RCC1_YEAST S000003065
246474 YOR204W YOR204W False YOR204W NaN sce:YOR204W 854379 DED1_YEAST S000005730

Create / Delete Table Data

Currently, you cannot delete the table or rows due to the Cytoscape data model design. However, it is easy to create / delete columns:

In [29]:
# Delete columns
yeast1.delete_node_table_column('kegg')

# Create columns
yeast1.create_node_column(name='New Empty Double Column', data_type='Double', is_immutable=False, is_list=False)

# Default is String, mutable column.
yeast1.create_node_column(name='Empty String Col')

yeast1.get_node_table().head()
Out[29]:
shared name name selected id foo entrez uniprot sgd New Empty Double Column Empty String Col
SUID
246470 YKR026C YKR026C False YKR026C NaN 853896 EI2BA_YEAST S000001734 NaN NaN
246471 YGL122C YGL122C False YGL122C NaN 852755 NAB2_YEAST S000003090 NaN NaN
246472 YGR218W YGR218W False YGR218W NaN 853133 XPO1_YEAST S000003450 NaN NaN
246473 YGL097W YGL097W False YGL097W NaN 852782 RCC1_YEAST S000003065 NaN NaN
246474 YOR204W YOR204W False YOR204W NaN 854379 DED1_YEAST S000005730 NaN NaN

Visual Styles

You can also use wrapper API to access Visual Styles.

Current limitations are:

  • You need to use unique name for the Styles
  • Need to know how to write serialized form of objects
In [30]:
# Get all existing Visual Styles
import json
styles = cy.style.get_all()
print(json.dumps(styles, indent=4))

# Create a new style
style1 = cy.style.create('sample_style1')

# Get a reference to the existing style
default_style = cy.style.create('default')

print(style1.get_name())
print(default_style.get_name())

# Get all available Visual Properties
print(len(cy.style.vps.get_all()))

# Get  Visual Properties for each data type
node_vps = cy.style.vps.get_node_visual_props()
edge_vps = cy.style.vps.get_edge_visual_props()
network_vps = cy.style.vps.get_network_visual_props()

print(pd.Series(edge_vps).head())
[
    "Universe",
    "Sample1",
    "Ripple",
    "Minimal",
    "default",
    "Solid",
    "Big Labels",
    "Nested Network Style",
    "Directed",
    "default black"
]
sample_style1
default
103
0                EDGE
1           EDGE_BEND
2         EDGE_CURVED
3          EDGE_LABEL
4    EDGE_LABEL_COLOR
dtype: object

Set default values

To set default values for Visual Properties, simply pass key-value pairs as dictionary.

In [31]:
# Prepare key-value pair for Style defaults

new_defaults = {
    # Node defaults
    'NODE_FILL_COLOR': '#eeeeff',
    'NODE_SIZE': 20,
    'NODE_BORDER_WIDTH': 0,
    'NODE_TRANSPARENCY': 120,
    'NODE_LABEL_COLOR': 'white',
    
    # Edge defaults
    'EDGE_WIDTH': 3,
    'EDGE_STROKE_UNSELECTED_PAINT': '#aaaaaa',
    'EDGE_LINE_TYPE': 'LONG_DASH',
    'EDGE_TRANSPARENCY': 120,
    
    # Network defaults
    'NETWORK_BACKGROUND_PAINT': 'black'
}

# Update
style1.update_defaults(new_defaults)

# Apply the new style
cy.style.apply(style1, yeast1)

Visual Mappings

In [32]:
# Passthrough mapping
style1.create_passthrough_mapping(column='name', col_type='String', vp='NODE_LABEL')

# Discrete mapping: Simply prepare key-value pairs and send it
kv_pair = {
    'pp': 'pink',
    'pd': 'green'
}
style1.create_discrete_mapping(column='interaction', 
                               col_type='String', vp='EDGE_STROKE_UNSELECTED_PAINT', mappings=kv_pair)

# Continuous mapping
points = [
    {
        'value': '1.0',
        'lesser':'white',
        'equal':'white',
        'greater': 'white'
    },
    {
        'value': '20.0',
        'lesser':'green',
        'equal':'green',
        'greater': 'green'
    }
]

minimal_style = cy.style.create('Minimal')
minimal_style.create_continuous_mapping(column='Degree', col_type='Double', vp='NODE_FILL_COLOR', points=points)

# Or, use utility for simple mapping
simple_slope = StyleUtil.create_slope(min=1, max=20, values=(10, 60))
minimal_style.create_continuous_mapping(column='Degree', col_type='Double', vp='NODE_SIZE', points=simple_slope)

# Apply the new style
cy.style.apply(minimal_style, scale_free100)

Layouts

Currently, this supports automatic layouts with default parameters.

In [33]:
# Get list of available layout algorithms
layouts = cy.layout.get_all()
print(json.dumps(layouts, indent=4))
[
    "attribute-circle",
    "stacked-node-layout",
    "degree-circle",
    "circular",
    "attributes-layout",
    "kamada-kawai",
    "force-directed",
    "grid",
    "hierarchical",
    "fruchterman-rheingold",
    "isom"
]
In [34]:
# Apply layout
cy.layout.apply(name='circular', network=yeast1)

yeast1.get_views()
yeast_view1 = yeast1.get_first_view()
node_views = yeast_view1['elements']['nodes']
df3 = pd.DataFrame(node_views)
df3.head()
Out[34]:
data position selected
0 {'sgd': 'S000002353', 'name': 'YDL194W', 'sele... {'y': 337.3408049125783, 'x': -816.2080368805437} False
1 {'sgd': 'S000002685', 'name': 'YDR277C', 'sele... {'y': 283.5470442679916, 'x': -768.351675592697} False
2 {'sgd': 'S000000247', 'name': 'YBR043C', 'sele... {'y': 700.0122446801881, 'x': 166.44780103059588} False
3 {'sgd': 'S000006349', 'name': 'YPR145W', 'sele... {'y': 549.1767770841686, 'x': -524.6571716355409} False
4 {'sgd': 'S000000856', 'name': 'YER054C', 'sele... {'y': -104.59739351311714, 'x': 1446.504571276... False

Embed Interactive Widget

In [35]:
from py2cytoscape.cytoscapejs import viewer as cyjs
cy.layout.apply(network=scale_free100)
view1 = scale_free100.get_first_view()
view2 = yeast1.get_first_view()
# print(view1)
cyjs.render(view2, 'default2', background='#efefef')
In [36]:
# Use Cytoscape.js style JSON
cyjs_style = cy.style.get(minimal_style.get_name(), data_format='cytoscapejs')
cyjs.render(view1, style=cyjs_style['style'], background='white')
In [ ]:
 

This website does not host notebooks, it only renders notebooks available on other websites.

Delivered by Fastly, Rendered by OVHcloud

nbviewer GitHub repository.

nbviewer version: d25d3c3

nbconvert version: 5.6.1

Rendered (Fri, 30 Sep 2022 18:39:44 UTC)