NoSQL Zone is brought to you in partnership with:

Max De Marzi, is a seasoned web developer. He started building websites in 1996 and has worked with Ruby on Rails since 2006. The web forced Max to wear many hats and master a wide range of technologies. He can be a system admin, database developer, graphic designer, back-end engineer and data scientist in the course of one afternoon. Max is a graph database enthusiast. He built the Neography Ruby Gem, a rest api wrapper to the Neo4j Graph Database. He is addicted to learning new things, loves a challenge and finding pragmatic solutions. Max is very easy to work with, focuses under pressure and has the patience of a rock. Max is a DZone MVB and is not an employee of DZone and has posted 59 posts at DZone. You can read more from them at their website. View Full User Profile

Graph Visualization and Neo4j

01.24.2012
| 8459 views |
  • submit to reddit

So far we’ve learned how to get Neo4j up and running with Neography, how to find friends of friends and degrees of separation with the Neo4j REST API and a little bit of the Gremlin and Cypher languages. However, all we’ve seen is text output. We haven’t really “seen” a graph yet, but that’s about to change.

Vouched holds a graph of skill specific recommendations people have made to each other and visualizes it. I extracted the visualization, and hosted it on github as neovigator. You can get your very own visualization up and running or take a look at this instance running on Heroku.


Let’s get it up and running and then we’ll go through some pieces of the code.

git clone git@github.com:maxdemarzi/neovigator.git
cd neovigator
bundle install
rake neo4j:install
rake neo4j:start
rackup

Then visit localhost:9292 to see it running.

The website is a Sinatra Application with only two routes. The home page, and a resources route that returns a JSON object of one node and all his “next node neighbours”.

The JSON object we create will have this structure:

{"details_html":"Information which replaces the side panel",
 "data":{
         "id":"the id of the current node",
         "name":"the name of the current node",
         "attributes":[{"id":"id of 1st relationship type",
                        "name":"name of 1st relationship type",
                        "values":[{"id":"the id of our 1st neighbour",
                                   "name":"the name of our 1st neighbour"},
                                  {"id":"the id of our 2nd neighbour",
                                   "name":"the name of our 2nd neighbour"}]},
                       {"id":"id of 2nd relationship type",
                        "name":"name of 2nd relationship type",
                        "values":[{"id":"the id of our 3rd neighbour",
                                   "name":"the name of our 3rd neighbour"},
                                  {"id":"the id of our 4th neighbour",
                                   "name":"the name of our 4th neighbour"}]}]
        }
}

When we fill this JSON object and pass it to the visualization, this is what we get:

We create a route in Sinatra and set it to return JSON.

get '/resources/show' do
  content_type :json

From our starting node, we are going to traverse the graph to a depth of 1, and get everything but our starting node.

neighbours =
  {"order"         => "depth first",
   "uniqueness"    => "none",
   "return filter" => {"language" => "builtin", "name" => "all_but_start_node"},
   "depth"         => 1}

Then we get our node and traverse the graph using the “fullpath” option which gives us the nodes and relationships.

node = neo.get_node(params[:id])
connections = neo.traverse(node, "fullpath", neighbours)

We are going to split up our incoming and outgoing relationships and get the ids of the “other node” so we can link to it.

incoming = Hash.new{|h, k| h[k] = []}
outgoing = Hash.new{|h, k| h[k] = []}

connections.each do |c|
   c["nodes"].each do |n|
     nodes[n["self"]] = n["data"]
   end
   rel = c["relationships"][0]

   if rel["end"] == node["self"]
     incoming["Incoming:#{rel["type"]}"] << {:values => nodes[rel["start"]].
                                                        merge({:id => node_id(rel["start"]) }) 
                                            }
   else
     outgoing["Outgoing:#{rel["type"]}"] << {:values => nodes[rel["end"]].
                                                        merge({:id => node_id(rel["end"]) }) 
                                            }
   end
end

We then merge them together to create our neighbours array and put them in the attributes piece of our JSON object.

incoming.merge(outgoing).each_pair do |key, value|
  attributes << {:id => key.split(':').last, 
                 :name => key, 
                 :values => value.collect{|v| v[:values]} 
                 }
end

We then load our JSON object with a few more details, like the node id, name, and some of its properties.

{:details_html => "<h2>Neo ID: #{node_id(node)}</h2>#{get_properties(node)}",
 :data => {:attributes => attributes,
           :name => node["data"]["name"],
           :id => node_id(node)}
 }.to_json
end

I will go over more details of how the visualization was done at FOSDEM 2012 in the Graph Processing Room on February 5th, 2012 at at 3:20 PM in the AW building room 1.125.

Credits
Processing is an open source programming language and environment for people who want to create images, animations, and interactions. Processing.js takes processing to the browser. It is written in JavaScript and uses HTML5′s canvas element. Michael Aufreiter adapted a motion tweening library for use with processing.js and built a radial navigator (Donut) for the project ASKKEN. Michael has given permission to use Donut as you’d like, checkout his amazing work with Substance.


Source:  http://maxdemarzi.com/2012/01/11/graph-visualization-and-neo4j/

Published at DZone with permission of Max De Marzi, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)