Today I want to introduce you to VivaGraphJS – a JavaScript Graph Drawing Library made by Andrei Kashcha of Yasiv. It supports rendering graphs using WebGL, SVG or CSS formats and currently supports a force directed layout. The Library provides an API which tracks graph changes and reflect changes on the rendering surface which makes it fantastic for graph exploration.
Today we will be integrating it with Neo4j and the Alchemy API.
The Alchemy API provides a set of natural language processing tools, and we’ll make use of their Entity Extraction capabilities.
We are going to take a look at the news of the world, extract the entities mentioned in them, connect them all together in Neo4j and visualize them. To get the news, we’ll use Feedzilla.
A sidekiq job will run every six hours to collect the latest 100 news articles:
module Job
class GetNews
include Sidekiq::Worker
sidekiq_options :retry => false
def perform
Job::GetNews.perform_in(6.hours)
feed = HTTPClient.get("http://api.feedzilla.com/v1/categories/19/articles.json?order=date&count=100&title_only=1")
parsed_feed = Oj.load(feed.body)
parsed_feed["articles"].each do |article|
Job::GetArticle.perform_async(article["url"])
end
end
end
end
From each article, we’ll get the story and pass it on to Alchemy API and ask it to find the entities in the article.
@entities = Oj.load(HTTPClient.post_content("http://access.alchemyapi.com/calls/url/URLGetRankedNamedEntities",
{:url => article_url,
:apikey => ENV['ALCHEMY_API'],
: outputMode => "json"}),
{:'Accept-encoding' => "gzip"})["entities"]
We’ll create a node for each article and connect each entity found by a “MENTIONED” relationship:
commands = []
@batch_result.each do |b|
commands << [:create_relationship, "MENTIONED", @article_node, b["body"]["self"].split("/").last]
end
Some of these entities have interesting descriptions, so we’ll query dbpedia for more information.
Moving on to our front-end application, we’ll provide an auto-complete search box which will query the Entities index of our graph:
get '/search' do
content_type :json
neo = Neography::Rest.new
cypher = "START me=node:entities({query})
RETURN ID(me), me.text
ORDER BY me.text
LIMIT 15"
neo.execute_query(cypher, {:query => "text:*#{params[:term]}* OR uri:*#{params[:term]}*" })["data"].map{|x| { label: x[1], value: x[0]}}.to_json
end
We’ll also provide an end-point to pull a node and all the nodes connected to it and return a JSON object with this data:
get '/edges/:id' do
content_type :json
neo = Neography::Rest.new
cypher = "START me=node(#{params[:id]})
MATCH me -- related
RETURN ID(me), me.text, me.description, me.type, ID(related), related.text, related.description, related.type"
connections = neo.execute_query(cypher)["data"]
connections.collect{|n| {"source" => n[0], "source_data" => {:label => n[1],
:description => n[2],
:type => n[3] },
"target" => n[4], "target_data" => {:label => n[5],
:description => n[6],
:type => n[7]}} }.to_json
end
Our javascript will contain the calls to Vivagraph:
var graph = Viva.Graph.graph();
var layout = Viva.Graph.Layout.forceDirected(graph, {
springLength:100,
springCoeff:0.0001,
dragCoeff:0.02,
gravity:-1
});
Our nodes will display both the Text found in the entity as well as an image to represent the entity type.
var ui = Viva.Graph.svg('g'),
svgText = Viva.Graph.svg('text').attr('y', '-4px').text(node.data.label),
img = Viva.Graph.svg('image')
.attr('width', 32)
.attr('height', 32)
.link('/img/' + node.data.type + '.png');
ui.append(svgText);
ui.append(img);
We’ll add a mouseover event to update the side-panel with the description of our node:
$(ui).hover(function() { // mouse over
highlightRelatedNodes(node.id, true);
$('#explanation').html(node.data.description);
}, function() { // mouse out
highlightRelatedNodes(node.id, false);
});
…and to load the nodes related to this entity on click:
$(ui).click(function() {
console.log("click", node);
if (!node || !node.position) return;
renderer.rerender();
loadData(graph,node.id);
}
);
As usual, the code is available on github, and you can see it running live on Heroku.
Check out some more of the Vivagraph.js demos:
- Amazon Visualization– Shows related products on Amazon.com, uses SVG as graph output
- YouTube Visualization – Shows related videos from YouTube. SVG based.
- Facebook Visualization – friendship visualization on Facebook. WebGL based.
- Graph Viewer – visualization of sparse matrices collection of the University of Florida. WebGL based.
- Vkontakte Visualization – friendship visualization of the largest social network in Russia vk.com. WebGL based.




I really love it :-)
I am very impressed. Wish you great success with it…
[…] Visualizing the news with Vivagraph.js (maxdemarzi.com) […]