Source | Persagen.com |
Author | Dr. Victoria A. Stuart, Ph.D. |
Created | 2019-08-20 |
Last modified | |
Summary | Visualization of data in Python using Cytoscape |
Related | KEGG Pathways Representation I: NetworkX |
Hello, again! This research blog post is a continuation of my KEGG Pathways Representation I: NetworkX research blog post.
The R programming language (with which I am acquainted) offers superb utilities for working with genomic data, e.g. via the Bioconductor package - which in turn includes the KEGGlincs utility for explicitly recreating KEGG pathway maps and overlaying NIH LINCS transcriptional data.
KEGGlincs can be used with Cytoscape, to visualize the graph (Cytoscape must be running in the background, for the CyREST interface layer interaction):
Pretty cool!
I've previously used Cytoscape, as I [Victoria Stuart] described and published here:
Stuart et al. (2009) Construction and Application of a Protein and Genetic Interaction Network (Yeast Interactome). Nucl. Acids Res. 37(7): e54.
Stuart et al. (2009) Transcriptional Response to Mitochondrial NADH Kinase Deficiency in Saccharomyces cerevisiae. Mitochondrion 9: 211-221.
Cytoscape is a mature, well supported and actively maintained platform that has progressed immeasurably since that time. Particularly relevant to the content of this research blog post are the following tools and resources that are available to Cytoscape.
For example, these are my glycolysis/TCA cycle pathway data, rendered in Cytoscape (here, just a basic visualization):
[2019-08-07] Cytoscape 3.7.1
* file:///mnt/Vancouver/programming/data/metabolism/data/relations2-glycolysis+tca.tsv
src_pw tgt_pw src_node tgt_node pathway vis wt
c00103_glycolysis 5.4.2.2_glycolysis c00103 5.4.2.2 1 vis wt
5.4.2.2_glycolysis c00668_glycolysis 5.4.2.2 c00668 1 vis wt
5.4.2.2_glycolysis c00103_glycolysis 5.4.2.2 c00103 1 vis wt
c00668_glycolysis 5.4.2.2_glycolysis c00668 5.4.2.2 1 vis wt
...
* Import - set:
source node: "src_pw" column
target node: "tgt_pw" column
source node attribute: "src_node" column
target node attribute: "tgt_node" column
edge attribute: rest {"pathway" | "vis" | "wt" columns}
* Node visual styles:
** Label: passthrough >> "src_node" column >> passthrough mapping
** ...
* Edge visual styles:
** Source arrow shape: none
** Target arrow shape: delta
** Label: "pathway" column >> passthrough mapping
** ...
* Bidirectional arrows:
** cannot set from edge visual styles; however, this worked:
*** Layout menu >> Bundle edges >> All nodes and edges >> Spring constant: 0.3 [default 0.003]
* Node positioning:
** import node positions (https://persagen.com/../../files/node_pos2x10.tsv)
[victoria@victoria misc]$ head -n5 node_pos2x10.tsv
node x y
c00103_glycolysis 200 60
5.4.2.2_glycolysis 200 70
c00267_glycolysis 80 80
2.7.1.1_glycolysis_a 140 75
2.7.1.2_glycolysis_a 140 80
2.7.1.147_glycolysis_a 140 85
3.1.3.9_glycolysis 140 90
c00668_glycolysis 200 80
5.3.1.9_glycolysis_c 170 100
...
** node visual properties >> add {X Location | Y Location} >> map the newly-imported "X", "y" columns per the passthrough mapping function
** View menu >> Show Tool Panel >> Node Layout Tools >> adjust vertical, horizontal node spacing ... [see video, below]
In my opinion, if you are familiar with the basic operation of Cytoscape the implementation of this visualization in Cytoscape was vastly superior / easier than the NetworkX implementation described in my first post!
This is demonstrated in my video screen capture, below, which shows that I can load those glycolysis / TCA data into Cytoscape and format the graph in less than 5-6 minutes!
Double-click (or mouseover → select "full screen" button at far right of progress bar) to enlarge:
Rather than further clutter this already lengthy post, I'll close by posting one of my raw text files that summarized a preliminary Cytoscape-related inquiry; that text includes a link to / implementation of the code that was used to generate the following py2cytoscape advanced cancer networks and data. visualization. My raw text file also shows some Python queries over those data.
>>> cytoscape.node.list_attributes()
['SUID',
'shared name',
'name',
'selected',
'canonical name',
'display name',
'full name',
'database identifier',
'description',
'@id',
'namespace',
'node type',
'query term',
'sequence',
'species',
'STRING style',
'enhancedLabel Passthrough',
'canonical',
'compartment cytoskeleton',
'compartment cytosol',
'compartment endoplasmic reticulum',
'compartment golgi apparatus',
'compartment mitochondrion',
'compartment nucleus',
'compartment plasma membrane',
'image',
'target development level',
'target family',
'tissue adrenal gland',
'tissue blood',
'tissue bone',
'tissue bone marrow',
'tissue eye',
'tissue gall bladder',
'tissue heart',
'tissue intestine',
'tissue kidney',
'tissue liver',
'tissue lung',
'tissue muscle',
'tissue nervous system',
'tissue pancreas',
'tissue saliva',
'tissue skin',
'tissue spleen',
'tissue stomach',
'tissue thyroid gland',
'tissue urine',
'disease score']
>>> disease_score_table=cytoscape.table.getTable(columns=['disease score'],table='node')
>>> disease_score_table.head()
disease score
9606.ENSP00000309913 2.998750
9606.ENSP00000349016 2.998750
9606.ENSP00000221992 2.569643
9606.ENSP00000322457 3.291596
9606.ENSP00000265171 2.937734
>>> import seaborn as sns
Traceback (most recent call last):
File "<console>, line 1, in <module>
ModuleNotFoundError: No module named 'seaborn'
## (needed to "pip install seaborn" in another py37 venv session)
>>> import seaborn as sns
>>> sns.set_style("white")
>>> sns.kdeplot( disease_score_table["disease score"] )
<matplotlib.axes._subplots.AxesSubplot object at 0x7feff43a1fd0>
>>> import matplotlib
>>> import matplotlib.pyplot as plt
>>> plt.xlabel("disease score")
Text(0.5, 0, 'disease score')
>>> plt.ylabel("frequency")
Text(0, 0.5, 'frequency')
>>> plt.show() ## file:///mnt/Vancouver/projects/files/cytoscape-automation-2019.07.05b.png
>>> top_quart=disease_score_table[["disease score"]].quantile(0.75)[0]
>>> top_quart
3.64357375
>>> top_nodes=disease_score_table[disease_score_table["disease score"]>top_quart].index.tolist()
>>> top_nodes
['9606.ENSP00000261769',
'9606.ENSP00000369497',
'9606.ENSP00000405330',
'9606.ENSP00000372023',
'9606.ENSP00000352271',
'9606.ENSP00000342235',
'9606.ENSP00000369816',
'9606.ENSP00000441765',
'9606.ENSP00000260947',
'9606.ENSP00000265433',
'9606.ENSP00000295736',
'9606.ENSP00000324856',
'9606.ENSP00000451974',
'9606.ENSP00000371194',
'9606.ENSP00000261584',
'9606.ENSP00000424328',
'9606.ENSP00000336701',
'9606.ENSP00000451828',
'9606.ENSP00000325120',
'9606.ENSP00000278616',
'9606.ENSP00000363804',
'9606.ENSP00000269571',
'9606.ENSP00000259008',
'9606.ENSP00000309572',
'9606.ENSP00000219746',
'9606.ENSP00000418960',
'9606.ENSP00000351273',
'9606.ENSP00000382423',
'9606.ENSP00000379683',
'9606.ENSP00000410294',
'9606.ENSP00000263967',
'9606.ENSP00000275493',
'9606.H19',
'9606.ENSP00000372088',
'9606.ENSP00000269305',
'9606.ENSP00000361021',
'9606.ENSP00000303939',
'9606.ENSP00000227507']
Please note: while the twp platforms share similar features, Cytoscape and Cytoscape.js are independent projects.
This is trivially easy! In the Cytoscape desktop application, with your data loaded, formatted and saved:
• Data/network: File menu → Export → Network to File... → Cytoscape.js JSON (*.cyjs)
• Styles: File menu → Export → Styles to File → Style for Cytoscape.js (*.json)
Here I made sure to also select my custom style (victoria_0) :
I am running Cytoscape.js locally via a webserver, manually run in a terminal.
# ============================================================================
## [npm] HTTP-SERVER:
## ==================
[victoria@victoria Vancouver]$ date
Tue 20 Aug 2019 04:05:56 PM PDT
## https://www.npmjs.com/package/http-server
## npm install http-server -g
## [partition] /home/victoria:
[victoria@victoria Vancouver]$ http-server
Starting up http-server, serving ./
Available on:
http://127.0.0.1:8080
http://192.168.1.4:8080
Hit CTRL-C to stop the server
^C
http-server stopped.
## [partition] /mnt/Vancouver:
[victoria@victoria Vancouver]$ http-server /mnt/Vancouver/
Starting up http-server, serving /mnt/Vancouver/
Available on:
http://127.0.0.1:8080
http://192.168.1.4:8080
Hit CTRL-C to stop the server
^C
http-server stopped.
[victoria@victoria Vancouver]$ cd ~
[victoria@victoria ~]$ pwd
/home/victoria
# ============================================================================
## [py3] HTTP.SERVER:
## ==================
## https://docs.python.org/3/library/http.server.html
[victoria@victoria ~]$ cd /mnt/Vancouver/programming/data/metabolism/practice/cytoscape/
## Python 3 webserver:
[victoria@victoria cytoscape]$ python -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
127.0.0.1 - - [20/Aug/2019 16:08:36] "GET /cytoscape_js.html HTTP/1.1" 304 -
127.0.0.1 - - [20/Aug/2019 16:08:37] "GET /data/styles.json HTTP/1.1" 304 -
127.0.0.1 - - [20/Aug/2019 16:08:37] "GET /data/relations2-glycolysis+tca.tsv.cyjs HTTP/1.1" 304 -
...
## ============================================================================
## LOCALHOST
http://localhost | http://127.0.0.1 | http://0.0.0.0
localhost ## i.e.: 127.0.0.1
127.0.0.1 ## i.e.: localhost
## Examples:
http://127.0.0.1:6006 ## (TensorFlow) TensorBoard [6006: googLE upside-down]
http://127.0.0.1:8993 ## Apache Solr
http://127.0.0.1:8888 ## Jupyter notebooks
http://192.168.1.1 ## router
http://localhost:631/ ## CUPS
http://localhost:631/printers ## CUPS: available printers {Brother MFC-9125CN | CUPS-PDF}
...
The webserver - which is needed to render JavaScript / jQuery code - provides a localhost URL / address - { http://localhost | http://127.0.0.1 | http://0.0.0.0 } - that you can access / open in a web browser, in order to view the served HTML document:
This first example describes the manual inclusion of the Cytoscape styles data in the HTML DOM (HTML document).
Here are the necessary files, available for download from my Persagen.com website.
Place the HTML file in the webserver root directory, with the other files places per this directory structure:
[victoria@victoria cytoscape]$ tree -L 2 -F
.
├── cytoscape.js.demo-external_styles.html
├── cytoscape.js.demo.html
└── data/
├── other/
├── relations2-glycolysis+tca.tsv.cyjs
├── styles-edited.json
└── styles.json
2 directories, 5 files
Refer to comments inside the HTML file for a greater understanding of this approach.
The JavaScript code contained within the cytoscape.js.demo-external_styles.html file is shown here.
Note that in this example I manually copied the styles data from styles.json to the cytoscape.js.demo-external_styles.html.
The $.getJSON() data structure, above, is a JavaScript / jQuery "promise" (see also this informative blog post).
The astute Reader will also notice that the edges in my pathways in the desktop Cytoscape application are bundled, which is the only way to show bidirectional arrows in Cytoscape. Per the comments in my HTML file, bundled edges unfortunately are not available (and not likely to be available) in Cytoscape.js. My workaround was to add the following line to the styles JSON code in the HTML code (and also in the external styles.json file):
// I added this to enable the display of arrows (bundled in cytoscape-3.7.1):
'curve-style': 'bezier'
While a satisfactory solution, bidirectionality in Cytoscape.js is indicated by paired unidirectional arrows.
For the following Cytoscape.js discussion, I've uploaded a tarball containing the needed files:
[victoria@victoria]$ tar -zcvf cytoscapejs_demo2.tgz *
cytoscape.js.demo.html
data/
data/styles-edited.json
data/styles.json
data/relations2-glycolysis+tca.tsv.cyjs
[victoria@victoria]$ date; ls -l
Wed 21 Aug 2019 12:22:53 PM PDT
total 32
-rw-r--r-- 1 victoria victoria 12923 Aug 21 12:22 cytoscapejs_demo2.tgz
-rw------- 1 victoria victoria 8516 Aug 21 12:06 cytoscape.js.demo.html
drwxr-xr-x 2 victoria victoria 4096 Aug 21 12:22 data
[victoria@victoria]$ tree -L 2 -F
.
├── cytoscapejs_demo2.tgz
├── cytoscape.js.demo.html
└── data/
├── relations2-glycolysis+tca.tsv.cyjs
├── styles-edited.json
└── styles.json
1 directory, 5 files
The files needed for this subsection are also available for direct download here, from my Persagen.com website:
Again, you'll need to run those files in a webserver.
The HTML file, cytoscape.js.demo.html, contains two approaches to loading the styles from external JSON file (hence the two styles files, above).
Here is the JavaScript portion of that HTML file, describing the two approaches.
// ==========================================================================
// APPROACH #1:
// Unedited "styles.json" file, exported from Cytoscape.
Promise.all([
fetch('data/relations2-glycolysis+tca.tsv.cyjs').then(res => res.json()),
fetch('data/styles.json').then(res => res.json())
]).then(([{elements}, [{style}]]) => {
cytoscape({
container: document.getElementById('cy'),
elements,
style,
// END, APPROACH #1-SPECIFIC CODE
// Note that we need, here, the (non-edited) Cytoscape-exported "styles.json" file.
// ==========================================================================
// ==========================================================================
// APPROACH #2: UNCOMMENT THIS (AND COMMENT APPROACH #1 LINES ABOVE):
// Manually edited "styles-edited.json" file.
// var json = $.getJSON('data/relations2-glycolysis+tca.tsv.cyjs')
// .done(function(data){
// var cy = cytoscape({
// container: document.getElementById('cy'),
// elements: data.elements,
// style: fetch('data/styles-edited.json').then(res => res.json()).then(json => json.style),
// END, APPROACH #2-SPECIFIC CODE
// Notes.
// 1. Here we need the (edited) Cytoscape-exported "styles.json" file: I
// needed to manually delete the leading "[ " at the top, and the lagging
// " ]" at the bottom of the Cytoscape-exported "styles.json" file:
// 2. This also works, but is not needed ("elements: data.elements" works):
// elements: fetch('data/relations2-glycolysis+tca.tsv.cyjs').then(res => res.json()).then(json => json.elements),
// ==========================================================================
// In either case, above, I added "curve-style" : "bezier" to the edge properties
// in the styles-edited.json file, to enable the display of the edges as arrows.
// ======================================================================
layout: {
// [ ... SNIP! ... ]
});
});
These solutions were very kindly provided by StackOverflow users Jaromanda X and maxkfranz, in response to my StackOverflow question. [Max Franz is also the leading - by a large margin - Cytoscape.js Contributor.]
Simple, once you know how! I hope that it helps others who seek this solution!
Sometimes you see (e.g. SO#45828931) the res => res.json() method predefined as follows:
let toJson = res => res.json();
let cy = new Cytoscape({
elements: fetch('some/cytoscape/elements.json').then( toJson ),
style: fetch('some/cytoscape/style.json').then( toJson ),
// ...
});
I'm not a fan of that usage:
In my opinion, the explicit statements are preferred.
Finally, after all that here is my metabolic network, fully loaded from external {data | styles} JSON files.
Enjoy! | Q.E.D.
Return to Persagen.com