This is a sample Jupyter Notebook to demonstrate how users can manipulate Cytoscape network views directly from Python code.
py2cytoscpae already has the Style API to create and update Visual Styles. There are different use cases for these two APIs:
In [1]:
from py2cytoscape.data.cynetwork import CyNetwork
from py2cytoscape.data.cyrest_client import CyRestClient
import pandas as pd
import json
# Create REST client for Cytoscape
cy = CyRestClient()
# Reset current session for fresh start
cy.session.delete()
# Load a sample network
network1 = cy.network.create_from('http://chianti.ucsd.edu/~kono/data/galFiltered.sif')
# You can check all available Visual Properties with this function call:
vps = pd.Series(cy.style.vps.get_all())
vps.head(20)
Out[1]:
There are twol options to get current views from Cytoscape:
CyNetworkView is a reference to a network view in your current Cytoscape session. This means CyNetworkView objects do not include actual data, such as node size or edge stroke colors. Instead, they hold a location of the data and create actual REST calls when you execute get/update methods for nodes and edges.
In [2]:
# Get views for a network: Cytoscape "may" have multiple views, and that's why it returns list instead of an object.
view_id_list = network1.get_views()
# Display IDs of available views
print(view_id_list)
# The "format" option specify the return type.
view1 = network1.get_view(view_id_list[0], format='view')
# This is a CyNetworkView object, not dictionary
print(view1)
In [3]:
view2 = network1.get_view(view_id_list[0], format='json')
#print(view2)
In [4]:
# Get node/edge views as a Python dictionary
node_views_dict = view1.get_node_views_as_dict()
edge_views_dict = view1.get_edge_views_as_dict()
#print(json.dumps(node_views_dict, indent=4))
#print(json.dumps(edge_views_dict, indent=4))
In [5]:
# Convert it into Pandas DataFrame
nv_df = pd.DataFrame.from_dict(node_views_dict, orient='index' )
# Extract specific Visual Property values...
node_location_df = nv_df[['NODE_X_LOCATION', 'NODE_Y_LOCATION']]
node_location_df.head()
Out[5]:
In [15]:
# Get views as NodeView/EdgeView objects
node_views = view1.get_node_views()
# Pick the first node view object
nv1 = node_views[0]
# Get details about the node
nv1_values = nv1.get_values()
# Convert to Data Frame
single_node_df = pd.DataFrame.from_dict(nv1_values, orient='index')
single_node_df.tail(20)
Out[15]:
In [16]:
# Access single value
nv1_color = nv1.get_value('NODE_FILL_COLOR')
print(nv1_color)
Setting values are also easy with py2cytoscape. All you have to do is creating a dictionary for the target nodes and edges.
If you call get/set methods for single node/edge view, it actually calls Cytoscape REST API through HTTP. If you need to update hundreds or thousands of nodes/edges, I strongly recommend update multiple objects at once.
In [53]:
# Switch current visual stye to a simple one...
minimal_style = cy.style.create('Minimal')
cy.style.apply(style=minimal_style, network=network1)
# Change background color: simply pass key-value pair
view1.update_network_view(visual_property='NETWORK_BACKGROUND_PAINT', value='black')
# Get SUID of all nodes
target_nodes = network1.get_nodes()
# Generate random colors for each node
import random
def get_color():
r = random.randint(0, 255)
g = random.randint(0, 255)
b = random.randint(0, 255)
return '#' + hex(r)[2:] + hex(g)[2:] + hex(b)[2:]
# Assign key-value pair. For this example, node SUID to color.
def generate_randome_color_dict(node_ids):
new_values = {}
for n in node_ids:
new_values[n] = get_color()
return new_values
new_values = generate_randome_color_dict(target_nodes)
# Set new values for a set of nodes. In this case, all nodes in the network
view1.update_node_views(visual_property='NODE_FILL_COLOR', values=new_values)
Now you can see something like this in the Cytoscape window. Let's embed the view as a static PNG image:
In [30]:
from IPython.display import Image
Image(network1.get_png())
Out[30]:
In [50]:
import math
all_nodes = network1.get_nodes()
idx = 0
x_locations = {}
for n in all_nodes:
x_locations[n] = idx*30
idx += 1
idx = 0
y_locations = {}
for n in all_nodes:
y_locations[n] = math.sin(idx/math.pi)*300
idx += 1
view1.update_node_views(visual_property='NODE_X_LOCATION', values=x_locations)
view1.update_node_views(visual_property='NODE_Y_LOCATION', values=y_locations)
Image(network1.get_png())
Out[50]:
In [60]:
def set_value(node_ids, val):
new_values = {}
for n in node_ids:
new_values[n] = val
return new_values
import math
import time
base_size = 30
for i in range(1,100):
mult = i * 0.2
view1.update_node_views(visual_property='NODE_TRANSPARENCY', values=set_value(node_ids, 30+abs(math.sin(mult/math.pi)*255 )))
view1.update_node_views(visual_property='NODE_WIDTH', values=set_value(node_ids, base_size + math.sin(i/math.pi)*10 ))
view1.update_node_views(visual_property='NODE_HEIGHT', values=set_value(node_ids, base_size + math.sin(i/math.pi)*10 ))
time.sleep(0.03)
In [66]:
from py2cytoscape.data.util_network import NetworkUtil as util
cy.style.apply(style=minimal_style, network=network1)
cy.layout.apply(name='force-directed', network=network1)
name_map = util.name2suid(network1)
center_node = name_map['YMR043W']
# Chenge Center node view
view1.update_node_views(visual_property='NODE_FILL_COLOR', values=set_value([center_node], 'yellow'))
view1.update_node_views(visual_property='NODE_WIDTH', values=set_value([center_node], 60))
view1.update_node_views(visual_property='NODE_HEIGHT', values=set_value([center_node], 60))
node_ids = network1.get_neighbours(center_node)
adj_edges = network1.get_adjacent_edges(center_node)
view1.update_edge_views(visual_property='EDGE_STROKE_UNSELECTED_PAINT', values=set_value(adj_edges, 'red'))
view1.update_node_views(visual_property='NODE_FILL_COLOR', values=set_value(node_ids, 'red'))
base_size = 30
for i in range(1, 200):
mult = i * 0.2
# view1.update_node_views(visual_property='NODE_TRANSPARENCY', values=set_value(node_ids, 30+abs(math.sin(mult/math.pi)*255 )))
view1.update_node_views(visual_property='NODE_WIDTH', values=set_value(node_ids, base_size + math.sin(i/math.pi)*10 ))
view1.update_node_views(visual_property='NODE_HEIGHT', values=set_value(node_ids, base_size + math.sin(i/math.pi)*10 ))
view1.update_edge_views(visual_property='EDGE_WIDTH', values=set_value(adj_edges, 3 + math.sin(i/math.pi)*2))
time.sleep(0.03)
In [67]:
# Grab list of nodes and edges
node_suids = network1.get_nodes()
edge_suids = network1.get_edges()
# DataFrame for node views
df1 = pd.DataFrame(index=node_suids,
columns=['NODE_FILL_COLOR', 'NODE_WIDTH', 'NODE_HEIGHT', 'NODE_X_LOCATION', 'NODE_Y_LOCATION'])
counter = 0
base_size = 40
for index, row in df1.iterrows():
row['NODE_FILL_COLOR'] = '#00FFaa'
row['NODE_WIDTH'] = base_size + math.sin(counter/math.pi)*(-30)
row['NODE_HEIGHT'] = base_size + math.sin(counter/math.pi)*(-30)
row['NODE_Y_LOCATION'] = math.sin(counter/math.pi)*200
row['NODE_X_LOCATION'] = counter*20
counter += 1
df1.head(10)
Out[67]:
In [69]:
# DataFrame for edge views
df2 = pd.DataFrame(index=edge_suids,
columns=['EDGE_WIDTH', 'EDGE_STROKE_UNSELECTED_PAINT'])
counter = 0
for index, row in df2.iterrows():
row['EDGE_STROKE_UNSELECTED_PAINT'] = '#aaaaaa'
row['EDGE_WIDTH'] = 2 + abs(math.sin(counter/math.pi)*5)
counter += 1
df2.head(10)
Out[69]:
In [70]:
# Apply it!
view1.batch_update_node_views(df1)
view1.batch_update_edge_views(df2)
In [72]:
Image(network1.get_png())
Out[72]:
In [76]:
from py2cytoscape.cytoscapejs import viewer as cyjs
cyjs.render(network1.get_first_view(), 'default2', background='#efefef')