KEGG pathways representation II: Cytoscape

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!

Cytoscape [desktop version]

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.

  • Cytoscape home  |  GitHub  |  Manual
  • Utilities; e.g.:
  • 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  c00103   1        vis  wt
    c00668_glycolysis   c00668    1        vis  wt
    c00103_glycolysis   c00103    1        vis  wt
            c00668_glycolysis  c00668   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 (
                [victoria@victoria misc]$ head -n5 node_pos2x10.tsv
                  node                    x    y
                  c00103_glycolysis       200  60
              200  70
                  c00267_glycolysis       80   80
            140  75
            140  80
          140  85
              140  90
                  c00668_glycolysis       200  80
            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!

  • The node positions defined in that video are available via my node_pos2x10.tsv file.

  • Demo [video]:

    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()
            'shared name',
            'canonical name',
            'display name',
            'full name',
            'database identifier',
            'node type',
            'query term',
            'STRING style',
            'enhancedLabel Passthrough',
            'compartment cytoskeleton',
            'compartment cytosol',
            'compartment endoplasmic reticulum',
            'compartment golgi apparatus',
            'compartment mitochondrion',
            'compartment nucleus',
            'compartment plasma membrane',
            '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')
          >>>    ## file:///mnt/Vancouver/projects/files/cytoscape-automation-2019.07.05b.png
          >>> top_quart=disease_score_table[["disease score"]].quantile(0.75)[0]
          >>> top_quart
          >>> top_nodes=disease_score_table[disease_score_table["disease score"]>top_quart].index.tolist()
          >>> top_nodes


    Please note: while the twp platforms share similar features, Cytoscape and Cytoscape.js are independent projects.

    Exporting Network and Styles Data from Cytoscape

    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
          ## npm install http-server -g
          ## [partition] /home/victoria:
          [victoria@victoria Vancouver]$ http-server
            Starting up http-server, serving ./
            Available on:
            Hit CTRL-C to stop the server
            http-server stopped.
          ## [partition] /mnt/Vancouver:
          [victoria@victoria Vancouver]$ http-server /mnt/Vancouver/
            Starting up http-server, serving /mnt/Vancouver/
            Available on:
            Hit CTRL-C to stop the server
            http-server stopped.
          [victoria@victoria Vancouver]$ cd ~
          [victoria@victoria ~]$ pwd
          # ============================================================================
          ## [py3] HTTP.SERVER:
          ## ==================
          [victoria@victoria ~]$ cd /mnt/Vancouver/programming/data/metabolism/practice/cytoscape/
          ## Python 3 webserver:
          [victoria@victoria cytoscape]$ python -m http.server
            Serving HTTP on port 8000 ( ...
   - - [20/Aug/2019 16:08:36] "GET /cytoscape_js.html HTTP/1.1" 304 -
   - - [20/Aug/2019 16:08:37] "GET /data/styles.json HTTP/1.1" 304 -
   - - [20/Aug/2019 16:08:37] "GET /data/relations2-glycolysis+tca.tsv.cyjs HTTP/1.1" 304 -
          ## ============================================================================
          ## LOCALHOST
          http://localhost  |  |
            localhost                             ## i.e.:
                               ## i.e.: localhost
          ## Examples:
                   ## (TensorFlow) TensorBoard [6006: googLE upside-down]
                   ## Apache Solr
                   ## Jupyter notebooks
                      ## 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 | | } - that you can access / open in a web browser, in order to view the served HTML document:

    Cytoscape.js styles: Internal JSON data [HTML DOM]

    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 website.

  • HTML file: cytoscape.js.demo-external_styles.html
  • Data (network) file: relations2-glycolysis+tca.tsv.cyjs
  • Styles file: styles.json
  • 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.

    Cytoscape.js styles: External JSON data file

    Data files:

    For the following Cytoscape.js discussion, I've uploaded a tarball containing the needed files:

  • cytoscapejs_demo2.tgz [12.9 KB]

          [victoria@victoria]$ tar -zcvf  cytoscapejs_demo2.tgz  *                                                                                
          [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 website:

  • HTML file: cytoscape.js.demo.html
  • Data (network) file: relations2-glycolysis+tca.tsv.cyjs
  • Styles file (raw Cytoscape export): styles.json
  • Styles file (edited Cytoscape export): styles-edited.json
  • 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. 
            fetch('data/relations2-glycolysis+tca.tsv.cyjs').then(res => res.json()),
            fetch('data/styles.json').then(res => res.json())
          ]).then(([{elements}, [{style}]]) => {
              container: document.getElementById('cy'),
          // Note that we need, here, the (non-edited) Cytoscape-exported "styles.json" file.
          // ==========================================================================
          // ==========================================================================
          // 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 =>,
          // 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:

  • It obfuscates the code.
  • It increases the probability of broken code; for example, if portions of the code are quoted elsewhere without the toJson definition.
  • There is very little compaction of the code: res ==> res.json() vs. toJson.
  • In my opinion, the explicit statements are preferred.

    Glycolysis + TCA cycle rendered in Cytoscape.js

    Finally, after all that here is my metabolic network, fully loaded from external {data | styles} JSON files.

    Demo [video]

    Enjoy!  |  Q.E.D.

    Return to