Сегодня я хочу познакомить вас с VivaGraphJS — библиотекой JavaScript Graph Graphing, созданной Андреем Кащей из Ясива . Он поддерживает рендеринг графиков с использованием форматов WebGL, SVG или CSS и в настоящее время поддерживает принудительную компоновку. Библиотека предоставляет API, который отслеживает изменения графиков и отражает изменения на поверхности рендеринга, что делает его фантастическим для исследования графиков.
Сегодня мы будем интегрировать его с Neo4j и Alchemy API .
Alchemy API предоставляет набор инструментов обработки естественного языка, и мы будем использовать их возможности Entity Extraction .
Мы собираемся взглянуть на новости мира, извлечь упомянутые в них сущности, соединить их все вместе в Neo4j и визуализировать их. Чтобы получать новости, мы будем использовать Feedzilla .
Задание sidekiq будет запускаться каждые шесть часов, чтобы собрать последние 100 новостных статей:
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
Из каждой статьи мы получим историю, передадим ее в Alchemy API и попросим найти сущности в статье .
@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"]
Мы создадим узел для каждой статьи и свяжем каждую сущность, найденную с помощью отношения «MENTIONED»:
commands = []
@batch_result.each do |b|
commands << [:create_relationship, "MENTIONED", @article_node, b["body"]["self"].split("/").last]
end
Некоторые из этих сущностей имеют интересные описания, поэтому мы запросим dbpedia для получения дополнительной информации.
Переходя к нашему клиентскому приложению , мы предоставим окно автозаполнения, которое будет запрашивать индекс сущностей нашего графика:
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
Мы также предоставим конечную точку для извлечения узла и всех узлов, подключенных к нему, и возврата объекта JSON с этими данными:
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
Наш javascript будет содержать обращения к Vivagraph:
var graph = Viva.Graph.graph();
var layout = Viva.Graph.Layout.forceDirected(graph, {
springLength:100,
springCoeff:0.0001,
dragCoeff:0.02,
gravity:-1
});
Наши узлы будут отображать как текст, найденный в объекте, так и изображение для представления типа объекта.
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);
Мы добавим событие mouseover, чтобы обновить боковую панель с описанием нашего узла:
$(ui).hover(function() { // mouse over
highlightRelatedNodes(node.id, true);
$('#explanation').html(node.data.description);
}, function() { // mouse out
highlightRelatedNodes(node.id, false);
});
… И загрузить узлы, связанные с этой сущностью, по клику:
$(ui).click(function() {
console.log("click", node);
if (!node || !node.position) return;
renderer.rerender();
loadData(graph,node.id);
}
);
Как обычно, код доступен на github , и вы можете увидеть, как он работает на Heroku .
Посмотрите еще несколько демонстраций Vivagraph.js:
- Amazon Visualization — показывает связанные продукты на Amazon.com, использует SVG в качестве вывода графика
- Визуализация YouTube — показывает похожие видео с YouTube. На основе SVG.
- Визуализация Facebook — визуализация дружбы на Facebook. На основе WebGL.
- Graph Viewer — визуализация коллекции разреженных матриц Университета Флориды. На основе WebGL.
- Вконтакте Визуализация — визуализация дружбы крупнейшей социальной сети в России vk.com . На основе WebGL.



