Use cytoscape.js to display neo4j network relationship diagram – 3. cytoscape.js

It is very interesting to display the network relationship diagram in a visual way. After choosing to use cytoscape.js to display the data of the neo4j graph database, I made a prototype and used the following three blogs to record the process of making the prototype .

  • Use cytoscape.js to display neo4j network relationship diagram – 1. Flask
  • Use cytoscape.js to display neo4j network relationship diagram – 2. py2neo
  • Use cytoscape.js to display neo4j network relationship diagram – 3. cytoscape.js (this blog)

Function to be completed

To correctly display the Movie data in the neo4j database to the front end, we need to complete the following functions.

  1. Build a simple website based on Flask
  2. Use py2neo to get neo4j nodes and relationships
  3. Use cytoscape.js to display network diagrams

The previous blog introduced how to use py2neo to obtain neo4j nodes and relationships, now we need to use cytoscape.js to display the nodes and relationships obtained with neo4j on the web page.

Let’s see what cytoscape.js is first

Cytoscape is a visualization tool for network graphs, which is used by a large number of companies in the field of biomolecules/genes for visual analysis. Due to its versatility, it is gradually being used by people in other fields for network visualization and analysis. Cytoscape is divided into two types, one is called cytoscape desktop, which is a desktop software that can import data and then generate a visualized network diagram for analysis; the other is called cytoscape.js, which is a javascript library, mainly for developers. Generate visualized network diagrams on web pages. We’re going to use the latter.

neo4j has three concepts: graph (Graph), node (Node) and relationship (Relationship). cytoscape.js also has three corresponding concepts: graph (generated with method cytoscape()), node (Node) and edge (Edge).

Below is a typical way to draw a graph with cytoscape.js.

var cy = cytoscape({
  container: document. getElementById('cy'),
  elements: {
    nodes: [/* ... */ ],
    edges: [/* ... */ ]
  },
  style: [ /* ... */ ],
  layout: { name: 'cose' }
});

Mainly use the cytoscape() function to generate cy and fill its various attributes (such as: container, elements, style, layout, etc.). Let’s write a simple web page to generate the graph below. All the codes are in an html file, you can save it as index.html, and then open it directly with a browser to see the effect.

Write picture description here

<!DOCTYPE html>
<html>
<head>
    <title>Learning Cytoscape.js</title>
    <style type="text/css">
        /* cytoscape graph */
        #cy {
            height: 300px;
            width: 400px;
            background-color: #f9f9f9;
        }
    </style>
    <script src="http://cdn.bootcss.com/jquery/1.11.2/jquery.min.js"></script>
    <script src="http://cdn.bootcss.com/cytoscape/2.3.16/cytoscape.min.js"></script>
    <script>
        $(function(){<!-- -->
            cytoscape({
              container: document. getElementById('cy'),
              style: [
                { selector: 'node[label = "Person"]',
                  css: {<!-- -->'background-color': '#6FB1FC', 'content': 'data(name)'}
                },
                { selector: 'node[label = "Movie"]',
                  css: {<!-- -->'background-color': '#F5A45D', 'content': 'data(title)'}
                },
                { selector: 'edge',
                  css: {<!-- -->'content': 'data(relationship)', 'target-arrow-shape': 'triangle'}
                }
              ],
              elements: {
                nodes: [
                  {data: {id: '172', name: 'Tom Cruise', label: 'Person'}},
                  {data: {id: '183', title: 'Top Gun', label: 'Movie'}}
                ],
                edges: [{data: {source: '172', target: '183', relationship: 'Acted_In'}}]
              },
              layout: {name: 'grid'}
            });
        });
    </script>
</head>
<body>
    <div id="cy"></div>
</body>
</html>

Lines 5-12 of the code set the properties of the graph, which is a graph with a length of 400px and a width of 300px with a gray background. On lines 15-40 of the code, we call the cytoscape() function and initialize it to complete the drawing of the relationship diagram.

On line 18 of the code, the container attribute is set to use the

div to draw the picture.

Lines 30-36 of the code, the elements attribute contains the nodes and edges in the graph.

The node includes multiple attribute values, such as: {data: {id: '172', name: 'Tom Cruise', label: 'Person'}}. Among them, only id is a reserved attribute that must be filled in. Others such as name and label are our custom attributes. You can customize as many attributes as you like.

The attribute values of edges and nodes are very similar, such as: {data: {source: '172', target: '183', relationship: 'Acted_In'}}. The edge also has an id which is a reserved attribute but is not required. Source/target are both reserved attributes. source represents the id value of the start node (start node), target is the id value of the end node (end node), and relationship is our custom attribute .

With the data of nodes and edges, how they are displayed is determined by the style attribute in lines 19-29 of the code. style consists of multiple (selector + css) styles as follows.

{ selector: 'node[label = "Person"]',
  css: {<!-- -->'background-color': '#6FB1FC','content': 'data(name)}
}

The selector attribute selects the element whose style is to be modified. Above we selected the node with label = "Person". css sets the style. Here we set the background color of the Person node to ‘#6FB1FC’. The content attribute determines what text is displayed on the node. We use a data() function to extract the custom node from the node data ({data: {id: '172' , name: 'Tom Cruise', label: 'Person'}}) in the name value, which is ‘Tom Cruise’.

{ selector: 'edge',
  css: {<!-- -->'content': 'data(relationship)', 'target-arrow-shape': 'triangle'}
} 

The style of edges is a bit different from that of nodes. The text we choose to display is the value of the relationship. And we need to display the triangle arrow of the side ('target-arrow-shape': 'triangle').

Code 37, layout attribute. layout The position displayed by the nodes in the layout network diagram. You can choose different types of layouts to display the entire network as a tree, circle, grid, force-directed graph, etc. We chose a ‘grid’ grid layout at random.

Start writing code

Let’s go back and look at the directory structure of the Flask website we built earlier. All source code below can be cloned from my github project cytoscape_neo4j.

C:\cytoscape_neo4j
| app.py
|
 + ---static
| + ---css
| | style.css
| |
| \---js
| code.js
|cytoscape.min.js
| jquery-1.11.2.min.js
|
\---templates
        index.html

We need to modify app.py and code.js. Let’s look at code.js first, it gets JSON data from app.py, and then calls the cytoscape() function to display the network graph.

Use cytoscape.js to display Movie network diagram

Below is the code for code.js. (source code: cytoscape_neo4j/static/js/code.js)

$(function(){<!-- -->
  $.get('/graph', function(result) {<!-- -->
    var style = [
      { selector: 'node[label = "Person"]', css: {<!-- -->'background-color': '#6FB1FC'}},
      { selector: 'node[label = "Movie"]', css: {<!-- -->'background-color': '#F5A45D'}}
    ];

    var cy = cytoscape({
      container: document. getElementById('cy'),
      style: style,
      layout: { name: 'cose', fit: false },
      elements: result. elements
    });
  }, 'json');
});

It is similar to the code mentioned above. Line 2 of the code, use jQuery’s $.get('/graph', function(result) {}, 'json') method to get it from the ‘/graph’ path on the backend of the website JSON data exists in result. The content of the JSON data is as follows:

{
  "elements": {
    "edges": [
      {"data": {"relationship": "ACTED_IN", "source": "174", "target": "327"}},
      {"data": {"relationship": "ACTED_IN", "source": "174", "target": "273"}},
      /* ... */
    ],
    "nodes": [
      {"data": {"id": "173", "label": "Movie", "released": 1999, "tagline": "Welcome to the Real World", "title": "The Matrix"}},
      {"data": {"born": 1962, "id": "189", "label": "Person", "name": "Tom Cruise "}},
      /* .. */
    ]
  }
} 

We only need to return the elements in the result to the elements attribute in the 12th line of the code, elements: result.elements.

Lines 3-6 of the code, the style is similar to what was mentioned above, this time we did not set the content attribute, so there will be no text on the displayed nodes.

Let’s see how app.py converts neo4j data into JSON that meets cytoscape requirements.

Convert neo4j data into JSON data required by cytoscape

Below is the code for app.py. (Source code: cytoscape_neo4j/app.py)

# coding=utf-8
from flask import Flask, jsonify, render_template
from py2neo import Graph

app = Flask(__name__)
graph = Graph()

def buildNodes(nodeRecord):
    data = {<!-- -->"id": str(nodeRecord.n._id), "label": next(iter(nodeRecord.n.labels))}
    data.update(nodeRecord.n.properties)

    return {<!-- -->"data": data}

def buildEdges(relationRecord):
    data = {<!-- -->"source": str(relationRecord.r.start_node._id),
            "target": str(relationRecord.r.end_node._id),
            "relationship": relationRecord.r.rel.type}

    return {<!-- -->"data": data}

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/graph')
def get_graph():
    nodes = map(buildNodes, graph. cypher. execute('MATCH (n) RETURN n'))
    edges = map(buildEdges, graph. cypher. execute('MATCH ()-[r]->() RETURN r'))

    return jsonify(elements = {<!-- -->"nodes": nodes, "edges": edges})

if __name__ == '__main__':
    app.run(debug = True)

This code uses a lot of py2neo functions. If you are not familiar with it, you can go back to the previous blog to see their usage.

$.get('/graph', function(result) {}, 'json') in code.js will call lines 25-30 in the code.

Code 27, nodes = map(buildNodes, graph.cypher.execute('MATCH (n) RETURN n')).

graph.cypher.execute('MATCH (n) RETURN n') gets all the nodes of the Movie library. map() calls the buildNodes(nodeRecord) function for each node to generate an array of nodes (eg [{"data": {"born": 1962, "id": "189" , "label": "Person", "name": "Tom Cruise"}}, /* node2*/, /* node3 */, ...]).

Line 28 of the code, edges = map(buildEdges, graph.cypher.execute('MATCH ()-[r]->() RETURN r')) generates all edges.

The code is 30 lines, using Flask’s jsonify function to convert elements into JSON format and return it to the front end.

Run our code!

With all the code written, it’s time to look at the fruits of our labor. Let’s fire up our website and see how the Movie library’s network diagram shows up. you need to:

  1. Start neo4j server
  2. Start the Flask website
  3. Browse the webpage with a browser http://127.0.0.1:5000/

Double-click C:\\
eo4j-community-2.2.1\bin\\
eo4j.bat
to start the neo4j server.

Run the following command to start the Flask website.
Write picture description here

Use a browser to browse the webpage http://127.0.0.1:5000/, and you can see the drawn network relationship diagram.
Write picture description here

The relationship diagram seen here is only a small part of the relationship diagram, you can use the mouse wheel to zoom in and out to see the whole picture.

At this point, you should know how to use neo4j, Flask, py2neo, cytoscape.js to display the network relationship diagram of neo4j through these three blogs.