• Cayley图数据库的可视化(Visualize)


    引入

      在文章Cayley图数据库的简介及使用中,我们已经了解了Cayley图数据库的安装、数据导入以及进行查询等。
      Cayley图数据库是Google开发的开源图数据库,虽然功能还没有Neo4J来得那么强大,但也有很多新的功能等待着我们去探索。本文将继续上篇文章的旅程,给读者介绍如何在Cayley图数据库中实现查询结果的可视化。
      下面,让我们一起来探究Cayley的奥秘吧~

    查询结果可视化

      Cayley图数据库的查询语句的参考网址为:https://github.com/cayleygraph/cayley/blob/master/docs/GizmoAPI.md 。 若想实现查询结果的可视化,则需要使用Tag()函数,返回的结果样式应当如下:

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

    即返回的结果中对节点会打上Tag,source为来源,颜色为蓝色,target为目的地,颜色为橙色。
      我们使用的数据仍来自文章Cayley图数据库的简介及使用 。 首先导入数据:

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

    接着启动查询语句的web界面:

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

    在浏览器中输入网址:http://localhost:64210 ,选择Visualize,

    输入命令:

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

    就能能到关系图的可视化结果了,如下:

      接着我们来查看某个实体的所有属性及属性值,输入的命令如下:

    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]);
    }
    

    出来的图如下:

    这样我们就实现了Cayley图数据库的可视化,但是效果一般,而且不支持对边赋值,因此无法在边上显示关系。

    利用D3.js实现可视化展示

      利用D3.js,我们可以把查询到的结果,自己来画关系图。笔者主要参考的项目的Github地址为: https://github.com/ownthink/KG-View/blob/master/index.html 。我们只需要将查询到的结果复制粘贴到该HTML文件中即可。还是以《流浪地球》的所有属性及属性值为例,查询的命令如下:

    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]);
    }
    

    返回的结果如下:

    {
    	"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"
    		}
    	]
    }
    

    将result的结果数组复制粘贴至index.html文件,内容如下:

    <!DOCTYPE html>
    <meta charset="utf-8">
    <style>.link {  fill: none;  stroke: #666;  stroke- 1.5px;}#licensing {  fill: green;}.link.licensing {  stroke: green;}.link.resolved {  stroke-dasharray: 0,2 1;}circle {  fill: #ccc;  stroke: #333;  stroke- 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>
    

    在浏览器中打开,效果如下:

    这个绘图的效果会比Cayley自带的效果好一些,但功能还是有限。

    总结

      网上关于Cayley的相关资料比较少,基本只有官方文档和社区作为参考。本文所讲述的内容如有不足之处,还请读者多多指教~另外,关于Cayley的可视化,如读者有更好地办法实现,也欢迎告知笔者~

    注意:不妨了解下笔者的微信公众号: Python爬虫与算法(微信号为:easy_web_scrape), 欢迎大家关注~

  • 相关阅读:
    Discuz论坛自动发帖机
    C#测试数据库连接是否成功
    JS重写提示框(confirm)
    随笔 选择
    随笔 诚实
    web项目经理手册【1】版本控制流程
    Asp.net多层架构中的变量引用与传递
    ASP.NET跨页面传值技巧总结
    web项目经理手册【3】Code Review
    web项目经理手册【7】项目经理需要铭记在心的话
  • 原文地址:https://www.cnblogs.com/jclian91/p/10675241.html
Copyright © 2020-2023  润新知