Network Visualizations with GRANDstack | by Tomaz Bratanic | Towards Data Science

Throughout the years, I have worked on a couple of Neo4j projects. Almost all the projects have in common that there was a need to develop a custom network visualization tool that would allow end-users to explore the graph without having to learn any Cypher query language syntax. This blog post will present a simple network visualization tool I have developed that lets you visualize and explore the Harry Potter universe. The visualization application is built using the GRANDstack. All the code is available on GitHub.
The GRANDstack consists of four components:
Neo4j database: Native graph database to store network data
GraphQL: Data query and manipulation language for APIs
Apollo: A suite of tools that work together to create GraphQL dataflows.
React: A JavaScript library for building component based reusable user interfaces
Neo4j is a native graph database suitable for storing, manipulating, and querying network data. If you are a complete Neo4j beginner and want to learn more, I suggest you look at the Neo4j introduction page.
The Harry Potter network data comes from a blog post I did a while back where I used NLP to extract connections between characters in the Harry Potter and the Philosopher’s Stone book. The graph schema model is as follows:
In the center of our graph are the book’s characters. Some of the characters belong to a Hogwarts house like Gryffindor or Slytherin. Characters are also loyal to various groups. For example, Hermione Granger is devoted to the Society for the Promotion of Elfish Welfare. The network also contains information about the family relationships between characters. Lastly, the interactions between characters are stored in the database as well. Here is a sample subgraph visualization around Harry Potter:
I have added both the dataset files as well as instructions on how to load the data into Neo4j in the GitHub repository.
GraphQL was initially developed by Facebook and later publicly released in 2015. GraphQL is a query language and server-side runtime for APIs that prioritizes giving clients precisely the data they request. A GraphQL service is created by defining types and fields on those types and then providing functions for each field. Neo4j has developed a GraphQL library that enables rapid development of a GraphQL server that interacts with a Neo4j database. In addition, the library automatically provides the functions needed to retrieve the types and fields defined in the GraphQL schema. Of course, you can always provide a custom resolver for any field if you want.
Here, I have defined two types in the schema. The type name must be identical to the node label in Neo4j. Neo4j GraphQL library offers full CRUD support by default. In our network visualization tool, we will only be reading the data from Neo4j and never updating the database. As we don’t need the full CRUD support, we can exclude the create, update, and delete mutations from being generated. You can include the properties of the nodes that should be available via the GraphQL endpoint the fields of a type.
For example, we could retrieve information about House or Group nodes in the client using these two schema types. A sample GraphQL query to retrieve information about House nodes is:
query house {   houses {     name   }}
And the result of this query is:
{ "data": {   "houses": [   { "name": "Gryffindor"},   { "name": "Slytherin"},   { "name": "Hufflepuff"},   { "name": "Ravenclaw"}]  }}
Well, that was easy! You don’t even need to know any Cypher query language for basic CRUD operations. Neo4j GraphQL library also offers support for pagination, sorting, and filtering queries out of the box. Read more about it in the documentation. Next, we can construct a schema type for a character.
The character type is a bit more complex. Here, we have introduced the @relationship directive. If you remember the graph schema, a character can belong to a house or be loyal to a group. To retrieve the information about the character’s house, we have to traverse the BELONGS_TO relationship. In the @relationshipdirective, you specify the type of relationship to be traversed and its direction. The direction of the relationship can either be outgoing or incoming.
Our application includes an autocomplete feature. We will use Neo4j’s Full-text search feature to achieve an autocomplete functionality on the frontend. You can define custom GraphQL queries under the Query type.
This is most of the code we needed to generate for our GraphQL server to interact with Neo4j. I have also added the interaction type, but it is pretty basic and doesn’t introduce additional functionalities, so I skipped it here.
Now that we have our database and GraphQL server ready, we can go ahead and develop the frontend. I have used the vis-react for network visualizations. I have chosen it because it exposes both the node/edge datasets and the network object. We need the node/edge datasets to create dynamic network visualizations, while the network object is used to add interactivity.
Apollo client library provides two React hooks for retrieving data from the GraphQL endpoint. The first is the useQuery hook. When a react component mounts and renders, the Apollo Client automatically executed a specified query. You can define the useQuery hook as follows:
First, you need to define the GraphQL query. Here, I specified I want to retrieve all characters that have the PageRank value greater than 0,16. In addition, I am only interested in the name, pagerank, and community fields, so I can specify the query to retrieve only those fields. Next, you can define the Reach Hook by using the useQuery functionality. Finally, the fetched data is combined with the interaction information and then input into the vis-react library to produce the following network visualization.
The second React hook provided by the Apollo Client library is the useLazyQuery . The useLazyQuery hook is designed for running queries in response to other events. For example, you can execute a query by clicking on the button or, in our case, by selecting a character from a selecting a node in the visualization to populate the popup.
The character’s data is then available in the function return under the characterData alias. Notice that I have used the where predicate in my GraphQL query to fetch the data of a specific character. I have used the react-modal library to generate popups, so the code looks like the following:
Sometimes you want to be able to access the GraphQL return within the function. In our example application, we need to return the autocomplete options to the input component from the function. To achieve this, you can access Apollo Client and wait for the query to finish with an async function.
By combining the auto-complete, popup, and other queries I have created the following network exploration component:
Hopefully, this blog post will help you get started with the GRANDstack and network exploration and visualizations. If you have any ideas how to improve this application please let me know in GH issues or create a Pull Request.
As always, the code is available on GitHub.