从neo4j中获取数据,并用echarts绘制成三层级力导向图

本文介绍了如何在Django项目中利用Echarts绘制三级力导向图。首先在Neo4j中创建节点和关系,然后通过Python查询并处理数据,返回前端展示。在前端,使用Echarts展示查询结果,同时展示关系列表。文章详细阐述了查询实体、处理数据和展示图表的步骤,包括关键代码和示例数据。
摘要由CSDN通过智能技术生成

Django项目时,要求根据绘制echarts三级力导向图,搜索了很多文章,好像都没有这种做法,因此记录一下。

如果对echarts绘力导向图还不是很了解,可以参考:

  Echarts绘制关系图(一) - 简书

功能: 在前端界面输入要查的实体,在neo4j中搜索后,显示与这个实体相连的三层级echarts图。

1. 先在neo4j中创捷节点和关系

CREATE(p:标签1{title:"实体"})
CREATE(p:标签1{title:"实体1"})
CREATE(p:标签1{title:"实体2"})
CREATE(p:标签1{title:"实体11"})
CREATE(p:标签1{title:"实体22"})

MATCH (e:标签1{title:"实体"}),(cc:标签1{title:"实体1"}) 
CREATE (e)-[:RELATION{type:"关系1"}]->(cc)

MATCH (e:标签1{title:"实体"}),(cc:标签1{title:"实体2"}) 
CREATE (e)-[:RELATION{type:"关系2"}]->(cc)

MATCH (e:标签1{title:"实体1"}),(cc:标签1{title:"实体11"}) 
CREATE (e)-[:RELATION{type:"关系11"}]->(cc)	

MATCH (e:标签1{title:"实体2"}),(cc:标签1{title:"实体22"}) 
CREATE (e)-[:RELATION{type:"关系22"}]->(cc)

   

 

2.   实体查询代码

  在relation_view.py定义search_entity函数,用来查找数据,并对数据进行处理

from toolkit.pre_load import neo_con
import os

def search_entity(request):
	ctx = {}
	#根据传入的实体名称搜索出关系
	if(request.GET):
		entity = request.GET['user_text']

		#连接数据库
		db = neo_con

		# 在entityRelation中第一个值记录实体2的数量
		entityRelation = []
		entityRelation = db.getEntityRelationbyEntity(entity)
		entitycount = len(entityRelation)

        # 添加第二层实体的实体名、关系
		for i in range(entitycount):
			
            # 获取第二层实体名称
			entity2 = {'entity2': entityRelation[i]['entity2']['title']}

            # 按照第二层实体名称查找第三层实体及其关系
			entityRelation_two = []
			entityRelation_two = db.getEntityRelationbyEntity(entity2['entity2'])

            # 将查到的第三层实体以及关系存储到nextRelation中
			entityRelation[i]['nextRelation'] = entityRelation_two

		if len(entityRelation) == 0:
			#若数据库中无法找到该实体,则返回数据库中无该实体
			ctx= {'title' : '<h1>数据库中暂未添加该实体</h1>'}
			return render(request,'entity.html',{'ctx':json.dumps(ctx,ensure_ascii=False)})
		else:
			#返回查询结果
			#将查询结果按照"关系出现次数"的统计结果进行排序
			entityRelation = sortDict(entityRelation)


			return render(request, 'entity.html', {'entityRelation': json.dumps(entityRelation, ensure_ascii=False)})
			
	return render(request,"entity.html",{'ctx':ctx})

 其中,相关的函数(neo_models.py)如下所示:

# 根据entity的名称返回关系
def getEntityRelationbyEntity(self, value):
	answer = self.graph.run("MATCH (entity1) - [rel] -> (entity2)  WHERE entity1.title = \"" +str(value)+"\" RETURN rel,entity2").data()
	return answer


def sortDict(relationDict):
	for i in range( len(relationDict) ):
		relationName = relationDict[i]['rel']['type']
		relationCount = relationCountDict.get(relationName)
		if(relationCount is None ):
			relationCount = 0
		relationDict[i]['relationCount'] = relationCount
	relationDict = sorted(relationDict,key = lambda item:item['relationCount'],reverse = True)
	return relationDict

      打印 entityRelation ,即通过search_entity处理后的数据,如图所示:

注意 此处的nextRelation是创建三层级的重点,后续就是根据nextRelation来判断此节点是否具有下层节点。

同理,如果想创建更多层级的数据,可以在对应的节点中加入nextRelation,将下层节点的信息存储其中。

       entity.html用于展示查询实体界面,后边嵌入js代码 ,对search_entity返回的数据做处理,并通过echarts显示。

{% extends "base.html" %} {% block mainbody %}

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
    <meta charset="utf-8" />
    <script src="/static/js/echarts.js"></script>
{#    <script type="text/javascript" src="http://echarts.baidu.com/gallery/vendors/echarts/echarts-all-3.js"></script>#}
</head>
<title>实体</title>
<div class="container">
    <div class="row">
    <!--head start-->
    <div class="col-md-12">
        <h3 class="page-header"><i class="fa fa-share-alt" aria-hidden="true"></i> 实体查询 </h3>
            <ol class="breadcrumb">
                <li><i class="fa fa-share-alt" aria-hidden="true"></i>实体查询</li>
            </ol>
    </div>
    <div class = "col-md-12">
        <div class="panel panel-default ">
            <header class = "panel-heading">
                查询条件:
            </header>
            <div class = "panel-body">
                <!--搜索框-->
                <form method = "get" id = 'searchEntityForm'>
                    <div >
                        <div class="input-group">
                            <input type="text" id = "user_text" name = "user_text" class="form-control" placeholder="输入实体名称" aria-describedby="basic-addon1">
                            <span class="btn btn-primary input-group-addon" type="button" id="relationSearchButton" style="background-color:#4592fe ; padding:6px 38px" onclick="document.getElementById('searchEntityForm').submit();">查询</span>
                         </div>
                    </div>
                </form>
            </div>
        </div>

        
    </div>
    <p>
        <div class = "col-md-12">
            {% if ctx %}
                <div class="panel panel-default">
                    <header class ="panel-heading">
                        <div class = "panel-body">
                            <h2>数据库中暂未添加该实体</h2>
                        </div>
                    </header>
                </div>
            {% endif %}
        </div>
    </p>
<!--relation start-->
{% if entityRelation %}
    <!-- entityRelation是relation_view.py中的 -->
    <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
    <div class = "col-md-12">
        <div class="panel panel-default ">
            <header class="panel-heading">
                关系图 :
            </header>
            <div class = "panel-body ">
                <div id="graph" style="width: 90%;height:600px;"></div>
            </div>
        </div>
    </div>
{% endif %}
{% if entityRelation %}
<div class = "col-md-12">
    <div class="panel panel-default">
    <header class="panel-heading">
        关系列表 :
    </header>
        <div class = "panel-body">
            <table class = "table" data-paging =  "true" data-sorting="true"></table>
        </div>
    </div>
</div>
{% endif %}
</div>
</div>
{% if entityRelation %}
<script src="/static/js/jquery.min.js"></script>
<script type="text/javascript">
        // 将后端的查询结果使用echarts展示
        var ctx = [ {{ ctx|safe }} ] ;

        //{entity2,rel}
        var entityRelation = [ {{ entityRelation|safe }} ] ;
        console.log(entityRelation);
        var data = [] ;
        var links = [] ;
        if(ctx.length == 0){
            var node = {} ;
            var url = decodeURI(location.search) ;
            var str = "";
            if(url.indexOf("?") != -1){
                str = url.split("=")[1]
            }
            //实体1
            node['name'] = str;
            //alert(document.getElementById('user_text').value)
            node['draggable'] = true ;
            var id = 0;
            node['id'] = id.toString() ;
            data.push(node) ;

            //获取实体2,存储在data中,如果实体2已经存在于data中,则不push
            var maxDisPlayNode = 15 ;
            for( var i = 0 ;i < Math.min(maxDisPlayNode,entityRelation[0].length) ; i++ ){
                node = {} ;
                node['name'] = entityRelation[0][i]['entity2']['title'] ;
               //  alert( entityRelation[0][i]['entity1']['title']);
                node['draggable'] = true ;//一个可拖动的段落:
                if('url' in entityRelation[0][i]['entity2']){
                    node['category'] = 1 ;
                }
                else{
                    node['category'] = 2 ;
                }
                id = i + 1
                node['id'] = id.toString();
                var flag = 1 ;
                relationTarget = id.toString() ;
                for(var j = 0 ; j<data.length ;j++){
                    if(data[j]['name'] === node['name']){
                        flag = 0 ;
                        relationTarget = data[j]['id']  ;
                        break ;
                    }
                }
                relation = {}
                relation['source'] = data[0]['id'] ;
                relation['target'] = relationTarget ;
                relation['category'] = 0 ;

                if(flag === 1){  //如果没有相同的节点,则push relation和node
                    data.push(node) ;
                    relation['value'] = entityRelation[0][i]['rel']['type'] ;
                    relation['symbolSize'] = 10
                    links.push(relation) ;
                }
                else{
                    //如果有相同的节点,则只push relation,不push node ,即不创建新的节点
                    relation['value'] = entityRelation[0][i]['rel']['type'] ;
                    relation['symbolSize'] = 10
                    links.push(relation) ;

                }

                //判断是否有下级,即,entityRelation[0][i]['nextRelation']中是否有数据,有的话循环添加
                var maxDisPlayNode = 15 ;
                for( var j = 0 ;j < Math.min(maxDisPlayNode,entityRelation[0][i]['nextRelation'].length) ; j++ ){
                    var flag = i;
                    node = {} ;
                    node['name'] = entityRelation[0][i]['nextRelation'][j]['entity2']['title'] ;
                    //  alert( entityRelation[0][i]['nextRelation']['entity1']['title']);

                    node['draggable'] = true ;//一个可拖动的段落:
                    node['category'] = 3 ;
                    id = 15*(i+1)+j+1 ;
                    node['id'] = id.toString();
                    var flag = 1 ;
                    relationTarget = id.toString() ;
                    for(var k = 0 ; k<data.length ;k++){
                        if(data[k]['name'] === node['name']){
                            flag = 0 ;
                            relationTarget = data[k]['id']  ;
                            break ;
                        }
                    }
                    relation = {} ;
                    var sourceId = i+1 ;
                    sourceId = sourceId.toString();
                    relation['source'] = sourceId ;
                    relation['target'] = relationTarget ;
                    relation['category'] = 1 ;
                    if(flag === 1){  //如果没有相同的节点,则push relation和node
                        data.push(node) ;
                        relation['value'] = entityRelation[0][i]['nextRelation'][j]['rel']['type'] ;
                        relation['symbolSize'] = 10
                        links.push(relation) ;
                    }
                    else{
                        //如果有相同的节点,则只push relation,不push node ,即不创建新的节点
                        relation['value'] = entityRelation[0][i]['nextRelation'][j]['rel']['type'] ;
                        relation['symbolSize'] = 10;
                        links.push(relation) ;

                    }
                }
           }

        }

        console.log(data);
        console.log(links);

        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('graph'));

        option = {
            title: {
                text: ''
            },//标题
            tooltip: {},//提示框配置
            animationDurationUpdate: 1500,
            animationEasingUpdate: 'quinticInOut',
            label: {//节点上的标签
                normal: {
                    show: true,
                    textStyle: {
                        fontSize: 12
                    },
                }
            },
            legend: {
                x: "center",
                show: false
            },
            series: [

                {
                    type: 'graph',
                    layout: 'force',
                    symbolSize: 60,
                    focusNodeAdjacency: true,
                    roam: true,
                    edgeSymbol: ['none', 'arrow'],
                    categories: [{
                        name: '查询实体',
                        itemStyle: {
                            normal: {
                                color: "#4592FF",
                            }
                        }
                    }, {
                        name: 'HudongItem',
                        itemStyle: {
                            normal: {
                                color: "#C71585",
                            }
                        }
                    }, {
                        name: 'NewNode',
                        itemStyle: {
                            normal: {
                                color: "#C71585",
                            }
                        }

                    },
                    {
                        name: 'NewNode',
                        itemStyle: {
                            normal: {
                                color: "#4592FF",
                            }
                        }

                    }],
                    label: {
                        normal: {
                            show: true,
                            textStyle: {
                                fontSize: 12,
                            },
                        }
                    },
                    force: {
                        repulsion: 800
                    },
                    edgeSymbolSize: [4, 50],
                    edgeLabel: {
                        normal: {
                            show: true,
                            textStyle: {
                                fontSize: 10
                            },
                            formatter: "{c}"
                        }
                    },
                    data : data,//节点
                    links: links,//节点间的关系

                    lineStyle: {//连接线的风格
                        normal: {
                            opacity: 0.9,
                            width: 1.3,
                            curveness: 0,
                            color:"#262626"
                        }
                    }
                }
            ]
        };

// 使用刚指定的配置项和数据显示图表。
        myChart.setOption(option);


            //用表格列出所有的关系
            tableData = []
            for (var i = 0 ; i < entityRelation[0].length ; i++){//想要得到某一行有多少列 可以写arr[0].length ,
                relationData = {} ;
                relationData['entity1'] = str ;
                relationData['relation'] = entityRelation[0][i]['rel']['type'] ;
                relationData['entity2'] = entityRelation[0][i]['entity2']['title'] ;
                tableData.push(relationData) ;

                for (var j = 0 ; j < entityRelation[0][i]['nextRelation'].length ; j++){
                    relationData = {} ;
                    relationData['entity1'] = entityRelation[0][i]['entity2']['title'] ;
                    relationData['relation'] = entityRelation[0][i]['nextRelation'][j]['rel']['type'] ;
                    relationData['entity2'] = entityRelation[0][i]['nextRelation'][j]['entity2']['title'] ;
                    tableData.push(relationData) ;

                }
            }

            jQuery(function(){
                $('.table').footable({
                "columns": [{"name":"entity1",title:"Entity1"} ,
                          {"name":"relation",title:"Relation"},
                          {"name":"entity2",title:"Entity2"}],
                "rows": tableData
                });
            });
</script>
{% endif %}

{% endblock %}

下图是打印出来的data的内容,可以看到data中主要存储各个节点的名字,id(很重要,并且必须是字符串,不能是数字,否则会出现错乱)

下图是打印出来的links的内容,可以看到links中主要存储两个节点之间的关系,source就是源节点的id, target是目标节点的id(再强调一遍,id为字符串)

3. 结果展示

  在实体查询界面输入要查询的 ”实体“,查询结果如图所示:

 

 

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要将Neo4j数据处理Echarts能读取的形式,并用Echarts显示出来,可以遵循以下步骤: 1. 安装py2neo和Echarts。 ``` pip install py2neo ``` 可以访问Echarts官方网站下载Echarts。 2. 从Neo4j数据库查询数据,并将其转换为Python列表。 ```python from py2neo import Graph graph = Graph("bolt://localhost:7687", auth=("neo4j", "password")) query = """ MATCH (a)-[:RELATION]->(b) RETURN a.name, b.name, COUNT(*) AS count """ result = graph.run(query) data = [] for row in result: data.append([row["a.name"], row["b.name"], row["count"]]) ``` 3. 将Python列表转换为Echarts需要的格式。假设我们要使用关系,将数据转换为Echarts需要的格式如下: ```python nodes = [] links = [] for item in data: source = item[0] target = item[1] value = int(item[2]) if source not in [node["name"] for node in nodes]: nodes.append({"name": source}) if target not in [node["name"] for node in nodes]: nodes.append({"name": target}) links.append({ "source": source, "target": target, "value": value }) echarts_data = { "nodes": nodes, "links": links } ``` 4. 使用EchartsJavaScript库将数据展示在网页上。可以使用以下代码生一个基本的关系: ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Echarts Demo</title> <script src="echarts.min.js"></script> </head> <body> <div id="chart" style="width: 800px;height:600px;"></div> <script> var chart = echarts.init(document.getElementById('chart')); var option = { title: { text: 'Neo4j Data', subtext: 'Relationship Graph' }, tooltip: {}, animationDurationUpdate: 1500, animationEasingUpdate: 'quinticInOut', series : [ { type: 'graph', layout: 'force', symbolSize: 50, roam: true, label: { normal: { show: true } }, edgeSymbol: ['circle', 'arrow'], edgeSymbolSize: [4, 10], edgeLabel: { normal: { textStyle: { fontSize: 20 } } }, data: echarts_data.nodes, links: echarts_data.links, force: { repulsion: 1000 } } ] }; chart.setOption(option); </script> </body> </html> ``` 5. 运行网页并查看结果。将上述代码保存为HTML文件并在浏览器打开,即可看到处理后的数据在网页以关系的形式展示出来。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值