Как я и обещал в моем предыдущем посте , я хотел бы сделать кое — что на D3.js .
Мы собираемся взять один из их примеров визуализации и визуализировать следующий график.
Чтобы создать наш график, мы возьмем имена 20 человек: создадим для них узлы, добавим их в индекс и случайным образом свяжем их вместе.
Обратите внимание, что мы используем команду Neography Batch для одновременного создания всего графика.
01 def create_graph
02 neo = Neography::Rest.new
03 graph_exists = neo.get_node_properties(1)
04 return if graph_exists && graph_exists['name']
05
06 names = %w[Max Agam Lester Musannif Adel Andrey Ryan James Bruce Tim Pinaki Mark Peter Anne Helene Corey Ben Rob Pramod Prasanna]
07
08 commands = names.map{ |n| [:create_node, {"name" => n}]}
09 names.each_index do |x|
10 commands << [:add_node_to_index, "nodes_index", "type", "User", "{#{x}}"]
11 follows = names.size.times.map{|y| y}
12 follows.delete_at(x)
13 follows.sample(1 + rand(5)).each do |f|
14 commands << [:create_relationship, "follows", "{#{x}}", "{#{f}}"]
15 end
16 end
17
18 batch_result = neo.batch *commands
19 end
Мы не будем делать ошибку, оставляя метод create_graph снова общедоступным, поэтому создадим для него задачу Rake.
1 require 'neography/tasks' 2 require './d3.rb' 3 4 namespace :neo4j do 5 task :create do 6 create_graph 7 end 8 end
Мы будем использовать Cypher для создания матрицы последователей, которую мы будем использовать для заполнения нашего скрипта D3.
1 def follower_matrix 2 neo = Neography::Rest.new 3 cypher_query = " START a = node:nodes_index(type='User')" 4 cypher_query << " MATCH a-[:follows]->b" 5 cypher_query << " RETURN a.name, collect(b.name)" 6 neo.execute_query(cypher_query)["data"] 7 end
Функция collect возвращает строку с массивом внутри нее, поэтому нам нужно немного перебрать строки, чтобы превратить ее в правильный массив, а затем преобразовать все в JSON.
1 get '/follows' do
2 follower_matrix.map{|fm| {"name" => fm[0], "follows" => fm[1][1..(fm[1].size - 2)].split(", ")} }.to_json
3 end
Наша функция D3 — небольшая вариация на примере аккордового аккорда в репозитории github D3:
01 var r1 = 960 / 2,
02 r0 = r1 - 120;
03
04 var fill = d3.scale.category20c();
05
06 var chord = d3.layout.chord()
07 .padding(.04)
08 .sortSubgroups(d3.descending)
09 .sortChords(d3.descending);
10
11 var arc = d3.svg.arc()
12 .innerRadius(r0)
13 .outerRadius(r0 + 20);
14
15 var svg = d3.select("body").append("svg")
16 .attr("width", r1 * 2)
17 .attr("height", r1 * 2)
18 .append("g")
19 .attr("transform", "translate(" + r1 + "," + r1 + ")");
20
21 d3.json("follows", function(follows) {
22 var indexByName = {},
23 nameByIndex = {},
24 matrix = [],
25 n = 0;
26
27 function name(name) {
28 return name
29 }
30
31 // Compute a unique index for each name.
32 follows.forEach(function(d) {
33 d = name(d.name);
34 if (!(d in indexByName)) {
35 nameByIndex[n] = d;
36 indexByName[d] = n++;
37 }
38 });
39
40 // Construct a square matrix counting relationships.
41 follows.forEach(function(d) {
42 var source = indexByName[name(d.name)],
43 row = matrix[source];
44 if (!row) {
45 row = matrix[source] = [];
46 for (var i = -1; ++i < n;) row[i] = 0;
47 }
48 d.follows.forEach(function(d) { row[indexByName[name(d)]]++; });
49 });
50
51 chord.matrix(matrix);
52
53 var g = svg.selectAll("g.group")
54 .data(chord.groups)
55 .enter().append("g")
56 .attr("class", "group");
57
58 g.append("path")
59 .style("fill", function(d) { return fill(d.index); })
60 .style("stroke", function(d) { return fill(d.index); })
61 .attr("d", arc);
62
63 g.append("text")
64 .each(function(d) { d.angle = (d.startAngle + d.endAngle) / 2; })
65 .attr("dy", ".35em")
66 .attr("text-anchor", function(d) { return d.angle > Math.PI ? "end" : null; })
67 .attr("transform", function(d) {
68 return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")"
69 + "translate(" + (r0 + 26) + ")"
70 + (d.angle > Math.PI ? "rotate(180)" : "");
71 })
72 .text(function(d) { return nameByIndex[d.index]; });
73
74 svg.selectAll("path.chord")
75 .data(chord.chords)
76 .enter().append("path")
77 .attr("class", "chord")
78 .style("stroke", function(d) { return d3.rgb(fill(d.source.index)).darker(); })
79 .style("fill", function(d) { return fill(d.source.index); })
80 .attr("d", d3.svg.chord().radius(r0));
81
82 });
Весь код доступен на Github .
Наконец, мы разместим все это на Heroku, как я уже показывал:
1 git clone git@github.com:maxdemarzi/d3_js_intro.git 2 cd d3_js_intro 3 bundle install 4 heroku create --stack cedar 5 heroku addons:add neo4j 6 git push heroku master 7 heroku run rake neo4j:create
Довольно, не правда ли?
Источник:
http://maxdemarzi.com/2012/02/02/graph-visualization-and-neo4j-part-three/

