Cayley graph database visualization (Visualize)

(Star Python developers to improve Python skills)

Author: jclian (This article from the Submission)

Introduce

In the article Introduction and Use of Cayley Graph Database , we have learned about the installation, data import and query of Cayley Graph Database.

The Cayley graph database is an open source graph database developed by Google. Although the function is not as powerful as Neo4J, there are many new functions waiting for us to explore. This article will continue the journey of the previous article and show readers how to visualize query results in the Cayley graph database. 

Next, let us explore the mystery of Cayley together~

Visualization of query results

  

The reference website for the query statement of the Cayley graph database is: https://github.com/cayleygraph/cayley/blob/master/docs/GizmoAPI.md. If you want to visualize the query results, you need to use the Tag() function, and the returned result style should be as follows:

[
{
  "source": "node1",
  "target": "node2"
},
{
  "source": "node1",
  "target": "node3"
},
]

That is, the node will be tagged with the tag in the returned result, the source is the source, the color is blue, and the target is the destination, the color is orange.

The data we use is still from the article Introduction and Use of Cayley Graph Database  . First import the data:

./cayley load -c cayley_example.yml -i data/China_Movie.nq

Then start the web interface of the query statement:

./cayley http -i ./data/China_Movie.nq -d memstore --host=:64210

Enter the URL in the browser: http://localhost:64210, select Visualize,

640?wx_fmt=png
Visualize

input the command:

g.V('<沈腾>').Tag("source").Out('<ACT_IN>').Tag("target").All();

You can get the visualization results of the relationship diagram, as follows:

640?wx_fmt=png

Then we look at all the attributes and attribute values ​​of an entity, the input command is as follows:

var eq = "<流浪地球>";
var attrs = g.V(eq).OutPredicates().ToArray(); 

values = new Array();
for (i in attrs) {
    var value = g.V(eq).Out(attrs[i]).ToValue();
    values[i] = value;
}

var s = new Array();


for (i in attrs) {
  var key_val_json = new Object();
  key_val_json["id"] = values[i];
  key_val_json["source"] = eq;
  key_val_json["target"]= attrs[i]+":"+values[i];
  s[i] = key_val_json;
}

for (i =0; i< s.length; i++) {
    g.Emit(s[i]);
}

The figure that comes out is as follows:

640?wx_fmt=png

In this way, we have realized the visualization of the Cayley graph database, but the effect is average, and the assignment of edges is not supported, so the relationship cannot be displayed on the edges.

Use D3.js to achieve visual display

Using D3.js, we can draw the relationship diagram by ourselves based on the query results. The Github address of the project that the author mainly refers to is: https://github.com/ownthink/KG-View/blob/master/index.html. We only need to copy and paste the query results into the HTML file. Taking all the attributes and attribute values ​​of "Wandering Earth" as an example, the query command is as follows:

var eq = "<流浪地球>";
var attrs = g.V(eq).OutPredicates().ToArray(); 

values = new Array();
for (i in attrs) {
    var value = g.V(eq).Out(attrs[i]).ToValue();
    values[i] = value;
}

var s = new Array();

for (i in attrs) {
  var key_val_json = new Object();
  key_val_json["source"] = eq;
  key_val_json["rela"] = attrs[i];
  key_val_json["target"] = values[i];
  key_val_json["type"] = "resolved";
  s[i] = key_val_json;
}

for (i =0; i< s.length; i++) {
    g.Emit(s[i]);
}

The results returned are as follows:

{
    "result": [
        {
            "rela": "<ISA>",
            "source": "<流浪地球>",
            "target": "<Movie>",
            "type": "resolved"
        },
        {
            "rela": "<rank>",
            "source": "<流浪地球>",
            "target": "2",
            "type": "resolved"
        },
        {
            "rela": "<src>",
            "source": "<流浪地球>",
            "target": "/item/%E6%B5%81%E6%B5%AA%E5%9C%B0%E7%90%83",
            "type": "resolved"
        },
        {
            "rela": "<box_office>",
            "source": "<流浪地球>",
            "target": "40.83亿",
            "type": "resolved"
        },
        {
            "rela": "<avg_price>",
            "source": "<流浪地球>",
            "target": "46",
            "type": "resolved"
        },
        {
            "rela": "<avg_people>",
            "source": "<流浪地球>",
            "target": "50",
            "type": "resolved"
        },
        {
            "rela": "<begin_date>",
            "source": "<流浪地球>",
            "target": "2019.02.05",
            "type": "resolved"
        }
    ]
}

Copy and paste the result array of result into the index.html file, the content is as follows:

<!DOCTYPE html>
<meta charset="utf-8">
<style>.link {  fill: none;  stroke: #666;  stroke-width: 1.5px;}#licensing {  fill: green;}.link.licensing {  stroke: green;}.link.resolved {  stroke-dasharray: 0,2 1;}circle {  fill: #ccc;  stroke: #333;  stroke-width: 1.5px;}text {  font: 12px Microsoft YaHei;  pointer-events: none;  text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff;}.linetext {    font-size: 12px Microsoft YaHei;}</style>
<body>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>
var links = 
[
    {
      "rela": "<ISA>",
      "source": "<流浪地球>",
      "target": "<Movie>",
      "type": "resolved"
    },
    {
      "rela": "<rank>",
      "source": "<流浪地球>",
      "target": "2",
      "type": "resolved"
    },
    {
      "rela": "<src>",
      "source": "<流浪地球>",
      "target": "/item/%E6%B5%81%E6%B5%AA%E5%9C%B0%E7%90%83",
      "type": "resolved"
    },
    {
      "rela": "<box_office>",
      "source": "<流浪地球>",
      "target": "40.83亿",
      "type": "resolved"
    },
    {
      "rela": "<avg_price>",
      "source": "<流浪地球>",
      "target": "46",
      "type": "resolved"
    },
    {
      "rela": "<avg_people>",
      "source": "<流浪地球>",
      "target": "50",
      "type": "resolved"
    },
    {
      "rela": "<begin_date>",
      "source": "<流浪地球>",
      "target": "2019.02.05",
      "type": "resolved"
    }
];
var nodes = {};
links.forEach(function(link)
{
  link.source = nodes[link.source] || (nodes[link.source] = {name: link.source});
  link.target = nodes[link.target] || (nodes[link.target] = {name: link.target});
});
var width = 1920, height = 1080;
var force = d3.layout.force()
    .nodes(d3.values(nodes))
    .links(links)
    .size([width, height])
    .linkDistance(180)
    .charge(-1500)
    .on("tick", tick)
    .start();
var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);
var marker=
    svg.append("marker")
    .attr("id", "resolved")
    .attr("markerUnits","userSpaceOnUse")
    .attr("viewBox", "0 -5 10 10")
    .attr("refX",32)
    .attr("refY", -1)
    .attr("markerWidth", 12)
    .attr("markerHeight", 12)
    .attr("orient", "auto")
    .attr("stroke-width",2)
    .append("path")
    .attr("d", "M0,-5L10,0L0,5")
    .attr('fill','#000000');
var edges_line = svg.selectAll(".edgepath")
    .data(force.links())
    .enter()
    .append("path")
    .attr({
          'd': function(d) {return 'M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y},
          'class':'edgepath',
          'id':function(d,i) {return 'edgepath'+i;}})
    .style("stroke",function(d){
         var lineColor;
         lineColor="#B43232";
         return lineColor;
     })
    .style("pointer-events", "none")
    .style("stroke-width",0.5)
    .attr("marker-end", "url(#resolved)" );
var edges_text = svg.append("g").selectAll(".edgelabel")
.data(force.links())
.enter()
.append("text")
.style("pointer-events", "none")
.attr({  'class':'edgelabel',
               'id':function(d,i){return 'edgepath'+i;},
               'dx':80,
               'dy':0
               });
edges_text.append('textPath')
.attr('xlink:href',function(d,i) {return '#edgepath'+i})
.style("pointer-events", "none")
.text(function(d){return d.rela;});
var circle = svg.append("g").selectAll("circle")
    .data(force.nodes())
    .enter().append("circle")
    .style("fill",function(node){
        var color;
        var link=links[node.index];
        color="#F9EBF9";
        return color;
    })
    .style('stroke',function(node){ 
        var color;
        var link=links[node.index];
        color="#A254A2";
        return color;
    })
    .attr("r", 28)
    .on("click",function(node)
    {
        edges_line.style("stroke-width",function(line){
            console.log(line);
            if(line.source.name==node.name || line.target.name==node.name){
                return 4;
            }else{
                return 0.5;
            }
        });
    })
    .call(force.drag);
var text = svg.append("g").selectAll("text")
    .data(force.nodes())
    .enter()
    .append("text")
    .attr("dy", ".35em")  
    .attr("text-anchor", "middle")
    .style('fill',function(node){
        var color;
        var link=links[node.index];
        color="#A254A2";
        return color;
    }).attr('x',function(d){
        var re_en = /[a-zA-Z]+/g;
        if(d.name.match(re_en)){
             d3.select(this).append('tspan')
             .attr('x',0)
             .attr('y',2)
             .text(function(){return d.name;});
        }

        else if(d.name.length<=4){
             d3.select(this).append('tspan')
            .attr('x',0)
            .attr('y',2)
            .text(function(){return d.name;});
        }else{
            var top=d.name.substring(0,4);
            var bot=d.name.substring(4,d.name.length);
            d3.select(this).text(function(){return '';});
            d3.select(this).append('tspan')
                .attr('x',0)
                .attr('y',-7)
                .text(function(){return top;});
            d3.select(this).append('tspan')
                .attr('x',0)
                .attr('y',10)
                .text(function(){return bot;});
        }
    });
function tick() {
  circle.attr("transform", transform1);
  text.attr("transform", transform2);
  edges_line.attr('d', function(d) { 
      var path='M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y;
      return path;
  });  

  edges_text.attr('transform',function(d,i){
        if (d.target.x<d.source.x){
            bbox = this.getBBox();
            rx = bbox.x+bbox.width/2;
            ry = bbox.y+bbox.height/2;
            return 'rotate(180 '+rx+' '+ry+')';
        }
        else {
            return 'rotate(0)';
        }
   });
}
function linkArc(d) {
  return 'M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y
}
function transform1(d) {
  return "translate(" + d.x + "," + d.y + ")";
}
function transform2(d) {
      return "translate(" + (d.x) + "," + d.y + ")";
}
</script>

Open in the browser, the effect is as follows:

640?wx_fmt=png
D3.js renderings

The effect of this drawing will be better than Cayley's built-in effect, but the function is still limited.

to sum up

  

There is relatively little information about Cayley on the Internet, and basically only official documents and communities are used as references. If there are any deficiencies in the content described in this article, please advise the readers~ In addition, about Cayley's visualization, if the reader has a better way to achieve it, please let me know~

[Author of this article]

jclian: I have been engaged in Python for more than two years. I am a Python enthusiast. I like algorithms and love to share. I hope to make more like-minded friends and go further on the road of learning Python together!

Think this article is helpful to you? Please share with more people

Pay attention to the "Python Developer" starred to improve Python skills

640?wx_fmt=png

Good article, I am reading ❤️

Guess you like

Origin blog.csdn.net/iodjSVf8U1J7KYc/article/details/100680930