精华内容
下载资源
问答
  • js实现知识图谱可视化,可移植性强,效果良好,我是用在了Django框架下,对于知识图谱查询结果的输出,也可以用在spring框架下。
  • 对Neo4j导出数据做知识图谱可视化 D3库实现

    千次阅读 多人点赞 2020-07-04 10:37:01
    知识图谱可视化 D3库的使用引言Neo4j导出数据 引言 好久没用D3库作可视化了,现在主要是用百度的echarts库,在项目中做简单的图表太方便了。但像是做关系图其实用echarts也很方便,这次用D3实现主要是复习一下以前做...

    一、引言

    好久没用D3库作可视化了,现在主要是用百度的echarts库,在项目中做简单的图表太方便了。但像是做关系图其实用echarts也很方便,这次用D3实现主要是复习一下以前做的东西,顺便记录一下。

    以下是我参考到的实例代码:

    二、从Neo4j导出数据

    1. 下载Neo4j Desktop

    官方下载链接:https://neo4j.com/download/

    注意下载后会跳转到Activation Key页面,这时已经自动生成好密钥,复制后,粘贴到 Neo4j DesktopSoftware Keys 输入框内即可完成激活:

    在这里插入图片描述

    2. 准备导入

    我们先通过Cypher查询将数据从Neo4j中查询出来,Neo4j构建和查询可以参考我上篇博客 基于Neo4j的外贸企业关系图谱做企业相似度查询

    由于原Cypher语句比较长,通过下面的查询导出的格式也是一样的,根据自己的关系查询进行修改即可:

    MATCH p=(n:Enterprise)-[]->() RETURN p limit 20
    

    查询后的结果如下,点击右上角下载图标,导出为JSON格式:

    在这里插入图片描述
    导出后,可以进入JSON在线解析,查看导出的JSON格式:
    在这里插入图片描述

    三、前端实现

    1. 初始化D3并读取本地数据

    新建好一个Web项目后,先把D3的JS库导入进来,再通过d3.json()来读取我们的json文件。

    可以通过本地方式导入

    <!-- 增加D3元素库 -->
    <script src="js/d3.v4.min.js"></script>
    

    如果不想下到本地,也可以通过CDN方式直接导入

    <!-- 增加D3元素库 -->
    <script src="https://cdn.bootcdn.net/ajax/libs/d3/4.9.1/d3.min.js"></script>
    

    导入D3后,就可以通过d3.json方法读取本地的json文件:

    var graph;
    //d3.json获取数据
    d3.json("data/records.json", function(error, data) {
    	if(error) throw error;
    	graph = data;
    	console.log(graph[0].p);
    }
    

    先运行结果,查看控制台打印的结果如下:
    `在这里插入图片描述

    2. 分离出节点和关系数据

    还是先去D3官方图实例参考分析一下标准数据格式,从下图可以看到 data 分为 nodeslinks 两部分,因为在D3中节点和关系是分开渲染的,渲染过后会自动在各个部分内生成位置坐标的属性。
    在这里插入图片描述
    此时我们需要将neo4j导出的数据做标准化,使数据格式符合D3标准。
    (需要注意一个坑:要对json数据做去重处理,不然D3在渲染时无法将节点关系弄出来,原理其实就是节点的唯一标识产生了冲突,我们要保证节点的唯一性)

    以下是标准化的代码,将json数据分离到 nodes 和 links 两部分,为数据绑定打好基础:(2021.04更新,解决长路径报错问题)

    // 图数据
    var graph;
    let nodes =[];
    let links = []; // 存放节点和关系
    let nodeSet = []; // 存放去重后nodes的id
    //d3.json获取数据
    d3.json(url, function(error, data) {
    	if (error) throw error
    	graph = data
    	console.log(graph[0].p)
    	for (let item of graph) {
    		for (let segment of item.p.segments) {
    			// 重新更改data格式
    			if (nodeSet.indexOf(segment.start.identity) == -1) {
    				nodeSet.push(segment.start.identity)
    				nodes.push({
    					id: segment.start.identity,
    					label: segment.start.labels[0],
    					properties: segment.start.properties
    				})
    			}
    			if (nodeSet.indexOf(segment.end.identity) == -1) {
    				nodeSet.push(segment.end.identity)
    				nodes.push({
    					id: segment.end.identity,
    					label: segment.end.labels[0],
    					properties: segment.end.properties
    				})
    			}
    			links.push({
    				source: segment.relationship.start,
    				target: segment.relationship.end,
    				type: segment.relationship.type,
    				properties: segment.relationship.properties
    			})
    		}
    	}
    	// 省略D3初始化代码...
    }
    

    3. 可视化效果展示

    数据处理好之后,只需要把数据绑定到D3上即可,至于展示部分官网参考代码已经有了,在此不再做详细展开,后面也可以参考我的代码注释理解。

    最终展示出的效果如下:

    在这里插入图片描述
    在这里插入图片描述
    从二图中可以看到可视化还做了一些事件处理,目前完成了拖拽事件、鼠标进入、鼠标离开三个事件。当鼠标放到节点上时,在右边会展示节点信息,并隐藏与该节点无关的其他节点。

    最后,加了个节点文字切换和搜索功能,之前的节点全挨在一起,于是又加了个碰撞检测模型,最终效果如下:

    在这里插入图片描述
    像这种力导向关系图可以结合多个力学模型自行扩充,其他的效果可以自行拓展:(官方参考的力模型)

    • Centering(向心力)
    • Collision(碰撞检测)
    • Links(弹簧力)
    • Many-Body(电荷力)
    • Positioning(定位力)

    4. 个人实现代码

    个人实现代码(仅供参考):

    四、代码修改说明(2021.04更新)

    1. 如何配置为自己的JSON数据

    <script> 标签中定位,修改如下几行代码即可,不需要在到处去找位置了

    // 自定义图标及颜色(数组保证一一对应)
    // names		图例名称变量制作图标
    // labels		节点的标签名称(与records.json中保证相同)
    // colors		图例颜色
    // url 			json文件的路径
    var names = ['企业', '贸易类型', '地区', '国家']
    var labels = ['Enterprise', 'Type', 'Region', 'Country']
    var colors = ['#55ffff', '#aaaaff', '#4e88af', '#ca635f']
    var url = 'data/records.json'
    

    2. 关于JSON格式正确但展示出错的问题

    之前的代码只支持 距离为1 的关系路径导入。

    如果你从Neo4j导出的 records.json 中关系路径长度大于1,比如下面这种情况会导致节点全部移至左上角。

    在这里插入图片描述
    现在已经修改完毕,支持长距离路径的图,只要满足JSON格式要求,即可进行可视化展示。

    3. 多图例颜色显示问题

    修复图例颜色问题,之前图例超过4个就无法填充颜色了,现在已更改

    多图例情况:(热心网友提供的数据,所以打个码)

    在这里插入图片描述

    4. 关于可视化展示

    这篇博客主要介绍如何处理Neo4j导出的JSON数据,没有展开来介绍图的可视化展示。正好最近试了一下新版的d3(v6版本),用vue对代码功能作进一步完善,更具体的可视化展示代码可以参考下面几篇博客:

    展开全文
  • 3D知识图谱可视化

    千次阅读 2020-12-01 21:43:18
    使用D3绘制的问题 比如在之前使用 vue+d3v6实现动态知识图谱可视化展示 存在明显的性能问题,该代码需要展示: 节点 关系 节点文字 关系文字 详情信息 动态交互及展示 以本人构建的外贸企业图谱为例,从Neo4j ...

    一、参考代码

    1. Github参考

    2. Demo参考

    https://bl.ocks.org/vasturiano/f59675656258d3f490e9faa40828c0e7

    在这里插入图片描述

    二、为什么使用3D做图谱可视化

    1. 背景

    知识图谱一般包含节点和关系两类数据,之前在做2D可视化展示时:

    主要是通过svg完成图形的绘制,而此时每一个节点、关系和文本都会对应一个DOM元素。如果为了做大规模知识图谱展示,当节点个数上千上万时,由于DOM操作的低效性,浏览器在可视化渲染到动态交互上都存在性能问题,此时应该减少DOM操作。

    这里简单介绍一下关于操作DOM对性能的影响,它会直接或间接地影响渲染引擎工作,而浏览器分为:渲染引擎JS引擎,再往下又涉及到浏览器渲染页面底层原理及过程,这里不再具体展开。

    其中 layout(布局)和paint(绘制)的性能消耗是最大的部分:

    • layout 就是布局变动造成重新计算(耗CPU,有时也很耗内存)
    • paint 就是调用浏览器UI引擎进行渲染展示页面(耗CPU和内存)

    总的来说,为了更好的展示大规模的知识图谱,需要用到3D技术,完成有限的区域容纳更多的节点信息。

    2. 使用D3绘制的问题

    比如在之前使用 vue+d3v6实现动态知识图谱可视化展示 存在明显的性能问题,该代码需要展示:

    • 节点
    • 关系
    • 节点文字
    • 关系文字
    • 详情信息
    • 动态交互及展示

    以本人构建的外贸企业图谱为例,从Neo4j Desktop中导出大小为3.7MB的JSON文件信息如下:

    • 节点个数:238
    • 关系个数:4908

    在这里插入图片描述
    可以看到有近20万行的JSON数据,如果加载该JSON,就会导致浏览器卡死。

    此时有几种优化思路:

    • 压缩JSON文件
      • 如:去除properties属性
      • 缺点:无法展示节点更多的详情信息
    • 2D图形使用Canvas代替SVG渲染,减少DOM开销
      • 缺点:
        • 图形交互上不如SVG
        • 图像放大时存在失真(SVG是矢量图)
    • 使用3D渲染
      • 缺点同上,因为3D也是Canvas
      • 优点:适合大规模的图谱展示场景

    2. 2D和3D渲染的对比(D3 vs Three)

    通过浏览器调试工具的 performance ,可以看到在分别使用2d和3d初始化页面时,浏览器执行的详细信息对比如下:

    • d3 做2d渲染(80节点和241关系)
      在这里插入图片描述

    • THREE 做3d渲染(300节点和300关系)
      在这里插入图片描述

    首先需要说明,在CPU和GPU的使用和占有率上来说,3d渲染肯定比2d要高。但是,从时间上来看,几百节点就已经看出明显的差距(Rendering/Painting/Idle),如果节点数量上万,可能会更明显。

    三、代码实现

    1. 安装第三方模块

    个人还是推荐使用第三方模块,这个东西的学习成本还是比较高的。。

    创建一个vue项目:

    vue create 3d-graph-demo
    

    安装3d-force-graph模块到项目依赖:

    npm i -S 3d-force-graph
    

    2. 具体代码

    库的导入

    在vue中导入3D库

    import ForceGraph3D from '3d-force-graph'
    // threejs的精灵标签,用于文字的展示
    import SpriteText from 'three-spritetext'
    

    初始化

    3d渲染的初始化代码,包括数据解析、数据渲染

    // 3d初始化,包括数据解析、数据渲染
    threeInit () {
      this.neoJsonParser(this.graph)
      this.threeRender()
    }
    

    其中解析(与2D代码相同)和渲染的函数如下:

    /*eslint-disable*/
    neoJsonParser (json) {
      const nodes =[]
      const links = [] // 存放节点和关系
      const nodeSet = [] // 存放去重后nodes的id
    
      for (let item of json) {
        for (let segment of item.p.segments) {
          // 重新更改data格式
          if (nodeSet.indexOf(segment.start.identity) == -1) {
            nodeSet.push(segment.start.identity)
            nodes.push({
              id: segment.start.identity,
              label: segment.start.labels[0],
              properties: segment.start.properties
            })
          }
          if (nodeSet.indexOf(segment.end.identity) == -1) {
            nodeSet.push(segment.end.identity)
            nodes.push({
              id: segment.end.identity,
              label: segment.end.labels[0],
              properties: segment.end.properties
            })
          }
          links.push({
            source: segment.relationship.start,
            target: segment.relationship.end,
            type: segment.relationship.type,
            properties: segment.relationship.properties
          })
        }
      }
      console.log(nodes)
      console.log(links)
      this.links = links
      this.nodes = nodes
      this.data = { nodes, links }
    }
    
    threeRender () {
      // DOM初始化及数据挂载
      const elm = document.getElementById('3d-graph')
      this.Graph = ForceGraph3D()(elm)
        .graphData(this.data)
    
      // 设置画布样式、节点及关系样式、事件绑定等
      this.Graph.height(750).width(1200)
        .backgroundColor('#000')
        // 节点样式和标签设置
        .nodeRelSize(7)
        .nodeColor(node => {
          let index = 0
          switch(node.label) {
            case 'Enterprise': break;
            case 'Type': index = 1;break;
            case 'Region': index = 2;break;
            default: index = 3;break;
          }
          return this.nodeColors[index]
        })
        // .nodeAutoColorBy('label')
        // 给节点添加文字
        // .nodeThreeObjectExtend(true)
        .nodeThreeObject(node => {
          const sprite = new SpriteText(node.properties.name)
          sprite.material.depthWrite = false // make sprite background transparent
          // 设置文字颜色
          let index = 0
          switch(node.label) {
            case 'Enterprise': break;
            case 'Type': index = 1;break;
            case 'Region': index = 2;break;
            default: index = 3;break;
          }
          sprite.color = this.nodeColors[index]
          sprite.textHeight = 8
          return sprite
        })
        .nodeThreeObjectExtend(true)
        .nodeLabel(node => `${node.label}: ${node.properties.name}`)
        .nodeOpacity(0.75)
        // 节点事件绑定
        .onNodeHover(node => elm.style.cursor = node ? 'pointer' : null)
        .onNodeClick(node => {
          console.log(node)
          //设置#info h4样式的颜色为该节点的颜色,文本为该节点name
          this.$set(this.selectNodeData, 'id', node.id)
          this.$set(this.selectNodeData, 'name', node.properties.name)
          // 获取节点类型对应的颜色
          let index = 0
          switch(node.label) {
            case 'Enterprise': break;
            case 'Type': index = 1;break;
            case 'Region': index = 2;break;
            default: index = 3;break;
          }
          this.$set(this.selectNodeData, 'color', this.nodeColors[index])
          this.$set(this.selectNodeData, 'properties', node.properties)
        })
        // 关系样式
        // .linkColor('#bbb')
        // .linkColor(link => {
        //   let index = 0
        //   const colors = ['#faa']
        //   switch(link.type) {
        //     case 'export': break;
        //     case 'type': index = 1;break;
        //     case 'locate': index = 2;break;
        //     default: index = 3;break;
        //   }
        //   return this.nodeColors[index]
        // })
        // .linkOpacity(1)
      
      // Spread nodes a little wider
      this.Graph.d3Force('charge').strength(-150)
    }
    

    四、效果展示

    最基础的展示效果,具体拓展可以去官方文档参考:

    在这里插入图片描述

    五、个人代码参考

    由于功能比较简单,现将代码集成到了 vue+d3v6实现动态知识图谱可视化展示 中,包括了2D/3D图谱展示两块内容。以下是代码地址,水平有限,仅提供参考,代码拓展请参考官方Github:

    六、总结

    本来准备做一万节点的对比,弄了一下发现直接卡死,所以暂时不用往下做了。。尴尬。。


    本博客完结,应该不会往下再做了,Web3D目前应用其实还是偏少一些,等以后有什么新技术火了说不定就用起来了。

    展开全文
  • ANTV G6知识图谱可视化入门案例

    千次阅读 2020-05-31 11:47:03
    目录源代码效果展示 源代码 先放代码,有时间再来写。。。 <!DOCTYPE html> <html lang="en"> <...meta name="viewport" content="width=device-width, initial-scale=1.0">...<

    源代码

    先放代码,有时间再来写。。。

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Demo</title>
    </head>
    
    <body>
        <div id='cxk'></div>
        <script src="https://gw.alipayobjects.com/os/antv/pkg/_antv.g6-3.5.0/dist/g6.min.js"></script>
        <script>
            const data = {
                nodes: [
                    {
                        id: 'node1',
                        label: '刘备',
                        type: 'circle',
                        chuohao: '刘皇叔',
                        zi: '玄德',
                    },
                    {
                        id: 'node2',
                        label: '诸葛亮',
                        type: 'circle',
                        zi: '孔明',
                    },
                    {
                        id: 'node3',
                        label: '关羽',
                        type: 'circle',
                        zi: '云长',
                    },
                    {
                        id: 'node4',
                        label: '曹操',
                        type: 'circle',
                        zi: '孟德',
                    },
                    {
                        id: 'node5',
                        label: '张飞',
                        type: 'circle',
                        zi: '翼德',
                    },
                    {
                        id: 'node6',
                        label: '孙权',
                        type: 'circle',
                        zi: '文台',
                    },
                    {
                        id: 'node7',
                        label: '周瑜',
                        type: 'circle',
                        zi: '公瑾',
                    },
                    {
                        id: 'node8',
                        label: '孙尚香',
                        type: 'circle',
                        zi: '',
                    },
                    {
                        id: 'node9',
                        label: '司马懿',
                        type: 'circle',
                        zi: '仲达',
                    },
                    {
                        id: 'node10',
                        label: '司马徽',
                        type: 'circle',
                        zi: '',
                    },
                    {
                        id: 'node11',
                        label: '郭嘉',
                        type: 'circle',
                        zi: '奉孝',
                    },
                    {
                        id: 'node12',
                        label: '夏侯渊',
                        type: 'circle',
                        zi: '妙才',
                    },
                ],
                edges: [
                    {
                        source: 'node1',
                        target: 'node2',
                        label: '谋士',
                    },
                    {
                        source: 'node1',
                        target: 'node3',
                        label: '结拜兄弟',
                    },
                    {
                        source: 'node1',
                        target: 'node4',
                        label: '政敌',
                    },
                    {
                        source: 'node1',
                        target: 'node5',
                        label: '结拜兄弟',
                    },
                    {
                        source: 'node1',
                        target: 'node6',
                        label: '政敌',
                    },
                    {
                        source: 'node6',
                        target: 'node7',
                        label: '谋士',
                    },
                    {
                        source: 'node6',
                        target: 'node8',
                        label: '妹妹',
                    },
                    {
                        source: 'node1',
                        target: 'node8',
                        label: '配偶',
                    },
                    {
                        source: 'node4',
                        target: 'node9',
                        label: '谋士',
                    },
                    {
                        source: 'node2',
                        target: 'node9',
                        label: '敌对',
                    },
                    {
                        source: 'node2',
                        target: 'node10',
                        label: '师傅',
                    },
                    {
                        source: 'node4',
                        target: 'node11',
                        label: '谋士',
                    },
                    {
                        source: 'node4',
                        target: 'node12',
                        label: '部下',
                    },
                    {
                        source: 'node3',
                        target: 'node5',
                        label: '结拜兄弟',
                    },
                    {
                        source: 'node10',
                        target: 'node9',
                        label: '侄儿',
                    },
                ],
            };
            const graph = new G6.Graph({
                container: 'cxk',
                width: 1800,
                height: 800,
                // fitView: true,
                // fitViewPadding: [20, 40, 50, 20],
                defaultEdge: {
                    type: 'cubic',
                    endArrow: true,
                    color: 'blue',
                    lineWidth: 12,
                    labelCfg:{
                        style:{
                            fontSize:20,
                        },
                    },
                },
                defaultNode:{
                    size:80,
                    style: {
                        fill: '#bae637',
                        stroke: '#eaff8f',
                        lineWidth: 5,
                    },
                    linkPoints: {
                        top: true,
                        bottom: true,
                        left: true,
                        right: true,
                        fill: 'skyblue',
                        size: 5,
                    },
                    labelCfg:{
                        style:{
                            fontSize:25,
                            fontFamily:'楷体',
                            fontWeight:1000,
                        },
                    },
                },
                layout: {
              type: 'force', 
              linkDistance: 400, 
              preventOverlap: true, 
              nodeSpacing:20,
            },
                modes: {
                    default: [
                        {
                            type: 'drag-node',
                        },
                        {
                            type: 'zoom-canvas',
    
                        },
                        {
                            type: 'activate-relations',
                        },
                        {
                            type: 'tooltip',
                            formatText(model) {
                                return '姓名:' + model.label + '<br/>字:' + model.zi;
                            },
                            offset: 15,
                        },
                        {
                            type: 'edge-tooltip',
                            formatText(model) {
                                return model.label;
                            },
                            offset: 15,
                        },
                        {
                            type: 'brush-select',
                        },
                    ],
                },
                nodeStateStyles: {
                    hover: {
                        fill: 'lightsteelblue',
                    },
                    click: {
                        stroke: '#000',
                        lineWidth: 3,
                    },
                },
                edgeStateStyles: {
                    click: {
                        stroke: '#000',
                        lineWidth: 3,
                    },
                },
            });
    
            graph.on('node:mouseenter', e => {
                const nodeItem = e.item; 
                graph.setItemState(nodeItem, 'hover', true); 
            });
            graph.on('node:mouseleave', e => {
                const nodeItem = e.item;
                graph.setItemState(nodeItem, 'hover', false); 
            });
            graph.on('node:click', e => {
                const clickNodes = graph.findAllByState('node', 'click');
                clickNodes.forEach(cn => {
                    graph.setItemState(cn, 'click', false);
                });
                const nodeItem = e.item; 
                graph.setItemState(nodeItem, 'click', true);
            });
            graph.on('edge:click', e => {
                const clickEdges = graph.findAllByState('edge', 'click');
                clickEdges.forEach(ce => {
                    graph.setItemState(ce, 'click', false);
                });
                const edgeItem = e.item; 
                graph.setItemState(edgeItem, 'click', true); 
            });
            graph.data(data);
            graph.render();
            main();
        </script>
        <style>
            .g6-tooltip {
                padding: 10px 6px;
                color: rgb(224, 28, 28);
                background-color: rgba(224, 223, 152, 0.9);
                border: 1px solid #000000;
                border-radius: 4px;
            }
        </style>
    </body>
    
    </html>
    

    效果展示

    在这里插入图片描述

    展开全文
  • 本文基于2008年至2017年纳入国家知识基础设施(CNKI)的总共3873项关于企业社会责任的研究,使用最新版本的Citespace软件分析... 通过对国内企业社会责任领域知识图谱的分析,将为该领域的未来研究提供有价值的参考。
  • Github ...整个可视化页面可全屏图像区域内 图形化展示概念名、关系名、关系概率(如有)非展示 id;未缩放时,图形展示可看清的大小,不一定展示全局。 单击概念,弹出概念选项: a.固定:固定节点位置.

    Github

    前端 vue.js + d3.js。

    需求

    上部区域

    • 展示所有的概念类别、以及画布内他们的个数
    • 展示所有关系类别,以及画布内他们的个数
    • 显示所有的概念场景(scenes 字段)、关系场景(source 字段)及画布的个数
    • 点击可选中和取消选中,取消选中时,批量隐藏对应的类别

    图像区域

    • 有按钮可控制缩放
    • 整个可视化页面可全屏图像区域内
    • 图形化展示概念名、关系名、关系概率(如有)非展示 id;未缩放时,图形展示可看清的大小,不一定展示全局。
    • 单击概念,弹出概念选项:
      a.固定:固定节点位置,展示其与可见的其他节点的关系;
      b.隐藏:隐藏该节点及其关系
      c.展开/收起:展开/收起该节点的所有直接关系及关系相连的节点(之前隐藏过也同样需展开)
    • 位置:
      a.已拖动过位置的节点,默认固定在最后停留位置
      b.未固定位置的节点,根据整体布局做调整
    • 悬停:
      a.悬停在节点时,高亮显示视野下该节点、节点关系、关系相连的概念
    • 视觉:
      a. 不同概念类别的节点,用不同颜色区分(详见设计图)

    下部区域

    • 展示选中的概念或关系的属性(悬停、单击)
    • 概念属性(id、概念类别、其他所有的数据属性等)
    • 关系属性(id、关系权重、其他关系属性)

    D3.vue

    <template>
      <div
        class="d3-container">
        <div
          class="types">
          <span
            v-for="(value, key, index) of typeCategories"
            :key="index"
            :style="{backgroundColor: typeColor[key]}"
            @mouseover="handleTypeMouseover(value, key)"
            @mouseout="handleTypeMouseout()">
            {{ key }}({{ value.length }})
          </span>
        </div>
        <div
          class="info">
          {{ info }}
        </div>
        <div
          class="btns">
          <span
            id="zoomIn">
            +
          </span>
          <span
            id="zoomOut">
            -
          </span>
          <span
            id="reset">
            reset
          </span>
        </div>
        <svg />
      </div>
    </template>
    
    <script>
    import * as d3 from 'd3'
    import mock from './mock.json'
    export default {
      data() {
        return {
          info: '',
          typeCategories: {},
          typeColor: {}, // 类型配色
          type: ['Disease', 'Symptom', 'Age', 'Sex', 'BodyStructure', 'Check', 'Thing', 'Severity', 'Population', 'Side', 'BetterAndWorse', 'Body', 'Aggravate', 'Imaging', 'Relieve', 'Event', 'Base', 'Finding', 'BodyStructure_test', 'Action', 'Time'], // 分类
          nodes: [], // 节点集
          links: [], // 关系集
          visibleFlag: false
        }
      },
      watch: {
        nodes: {
          handler(val) {
            // 监听节点变化,设置类型标签
            const obj = {}
            val.forEach(e => {
              if (Object.keys(obj).indexOf('' + e.semantic_type) === -1) {
                obj[e.semantic_type] = []
              }
              obj[e.semantic_type].push(e)
            })
            this.typeCategories = obj
          },
          deep: true
        }
      },
      mounted() {
        this.setTypeColor()
        this.initD3()
      },
      methods: {
        handleTypeMouseout() {
          d3.selectAll('.single-node').style('opacity', 1)
          d3.selectAll('.single-line').style('opacity', 1)
        },
        handleTypeMouseover(data) {
          d3.selectAll('.single-node').style('opacity', 0.1)
          d3.selectAll('.single-line').style('opacity', 0.1)
          for (let i = 0; i < data.length; i++) {
            const nodeID = '#single-node' + data[i].id
            d3.selectAll(nodeID).style('opacity', 1)
          }
        },
        setTypeColor() {
          const obj = {}
          this.type.forEach(e => {
            if (Object.keys(obj).indexOf('' + e) === -1) {
              obj[e] = ''
            }
            obj[e] = this.randomColor()
          })
          this.typeColor = obj
        },
        randomColor() {
          const colors = ['#F4AB87', '#EEC88D', '#76CADF', '#97DA9D', '#88DCD8', '#FB7F89', '#F0E403', '#F576BE', '#ACADFF', '#7EC3FB', '#D0DB02', '#C07B11', '#00ACC2', '#2AAD41', '#A59D00', '#EB4747', '#CD0EBD', '#DE3997']
          return colors[Math.floor(Math.random() * colors.length)]
        },
        initD3() {
          const _this = this
          // 数据示例
          // nodes = [
          //   { id: 'a', name: 'a' },
          //   { id: 'b', name: 'b' },
          //   { id: 'c', name: 'c' }
          // ]
          // links = [
          //   { id: 'ab', source: 'a', target: 'b' },
          //   { id: 'bc', source: 'b', target: 'c' }
          // ]
    
          // 容器
          const svg = d3.select('svg')
            .attr('viewBox', [-window.innerWidth / 2, -window.innerHeight / 2, window.innerWidth, window.innerHeight])
    
          // 缩放
          const zoom = d3.zoom()
            .on('zoom', function () {
              svg.attr('transform', d3.zoomTransform(svg.node()))
              // const tran = d3.zoomTransform(svg.node())
              // const _k = tran.k
              // console.log(tran)
              // console.log(Math.floor(_k * 100) / 100)
            })
          svg.call(zoom)
    
          d3.select('#reset')
            .on('click', function () {
              svg.call(zoom.transform, d3.zoomIdentity)
            })
          d3.select('#zoomIn')
            .on('click', function () {
              zoom.scaleBy(svg, 1.1)
            })
          d3.select('#zoomOut')
            .on('click', function () {
              zoom.scaleBy(svg, 0.9) // 执行该方法后 会触发 zoom 事件 0.9 缩小
            })
    
          // 新建一个力导向图
          const simulation = d3.forceSimulation()
            .force('charge', d3.forceManyBody().strength(-1000))
            .force('link', d3.forceLink().id(d => d.id).distance(200))
            .force('x', d3.forceX())
            .force('y', d3.forceY())
            .on('tick', ticked)
    
          // 关系路径
          let link = svg.append('g')
            .attr('class', 'link-container')
            .attr('stroke', '#000')
            .attr('stroke-width', 1)
            .selectAll('line')
    
          // 关系文字
          let linkText = svg.append('g')
            .attr('class', 'link-text-container')
            .attr('stroke', '#000')
            .attr('stroke-width', 1.5)
            .selectAll('text')
    
          // 节点
          let node = svg.append('g')
            .attr('class', 'node-container')
            .selectAll('circle')
    
          function ticked() {
            node
              .attr('transform', function (d) {
                return 'translate(' + d.x + ',' + d.y + ')'
              })
    
            link.attr('x1', d => d.source.x)
              .attr('y1', d => d.source.y)
              .attr('x2', d => d.target.x)
              .attr('y2', d => d.target.y)
    
            linkText
              .attr('x', d => (d.source.x + d.target.x) / 2)
              .attr('y', d => (d.source.y + d.target.y) / 2)
          }
    
          // 更新
          const updateObj = Object.assign(svg.node(), {
            update({ nodes, links }) {
              // 做一个浅复制,以防止突变,回收旧节点以保持位置和速度
              const old = new Map(node.data().map(d => [d.id, d]))
              nodes = nodes.map(d => Object.assign(old.get(d.id) || {}, d))
              links = links.map(d => Object.assign({}, d))
    
              // 节点
              node = node
                .data(nodes, d => d.id)
                .join(
                  enter =>
                    enter.append('g')
                      .attr('class', 'single-node')
                      .attr('id', (d) => {
                        return 'single-node' + d.id
                      })
                )
                .call(d3.drag()
                  .on('start', dragstarted)
                  .on('drag', dragged)
                  .on('end', dragended))
              d3.selectAll('.single-node')
                .append('circle')
                .attr('r', 30)
                .attr('fill', nodeColor)
                .style('cursor', 'pointer')
              // 节点文字
              d3.selectAll('.single-node')
                .append('text')
                .attr('y', 0)
                .attr('dy', 5)
                .attr('text-anchor', 'middle')
                .style('cursor', 'pointer')
                .attr('x', function (d) {
                  return textBreaking(d3.select(this), d, false)
                })
    
              // 绘制箭头
              svg.append('g')
                .attr('class', 'arrow-marker')
                .append('marker')
                .attr('id', 'arrow-marker')
                .attr('markerUnits', 'strokeWidth') // 设置为 strokeWidth 箭头会随着线的粗细发生变化
                .attr('markerUnits', 'userSpaceOnUse')
                .attr('viewBox', '0 -5 10 10') // 坐标系的区域
                .attr('refX', 40) // 箭头坐标
                .attr('refY', 0)
                .attr('markerWidth', 10) // 标识的大小
                .attr('markerHeight', 10)
                .attr('orient', 'auto') // 绘制方向,可设定为:auto(自动确认方向)和 角度值
                .attr('stroke-width', 2) // 箭头宽度
                .append('path')
                .attr('d', 'M0,-5L10,0L0,5') // 箭头的路径
                .attr('fill', '#000') // 箭头颜色
    
              // 关系路径
              link = link
                .data(links, d => [d.source, d.target])
                .join(
                  enter =>
                    enter.append('line')
                      .attr('class', 'single-line')
                      .attr('id', (d) => {
                        return 'single-line' + d.id
                      })
                      .attr('marker-end', 'url(#arrow-marker)') // 根据箭头标记的 id 号标记箭头
                )
    
              // 路径文字
              linkText = linkText
                .data(links, d => [d.source, d.target])
                .join(
                  enter =>
                    enter.append('text')
                      .attr('class', 'link-text')
                      .attr('id', (d) => {
                        return 'link-text' + d.id
                      })
                      .text((d) => {
                        return d.semantic_type
                      })
                      .attr('stroke', '#000')
                      .attr('stroke-width', '1')
                      .attr('fill', 'none')
                      .style('cursor', 'pointer')
                )
    
              simulation.nodes(nodes)
              simulation.force('link').links(links)
              simulation.alpha(1).restart()
    
              node
                .on('click', function (d) {
                  _this.visibleFlag = !_this.visibleFlag
                  toggleMenu(d3.select(this), d, _this.visibleFlag)
                })
                .on('mouseover', function (d) {
                  // 鼠标移入节点,高亮当前节点及与当前节点有关系的路径和节点
                  d3.selectAll('.single-node').style('opacity', 0.2)
                  d3.selectAll('.single-line').style('opacity', 0.2)
                  d3.selectAll('.link-text').style('opacity', 0.2)
                  d3.select('#single-node' + d.id).style('opacity', 1)
                  const relationLinks = []
                  _this.links.forEach((item) => {
                    if (item.source === d.id || item.target === d.id) {
                      relationLinks.push(item)
                    }
                  })
                  relationLinks.forEach((item) => {
                    d3.select('#single-line' + item.id).style('opacity', 1)
                    d3.select('#link-text' + item.id).style('opacity', 1)
                    d3.select('#single-node' + item.source).style('opacity', 1)
                    d3.select('#single-node' + item.target).style('opacity', 1)
                  })
                  _this.info = JSON.stringify(d)
                })
                .on('mouseout', function () {
                  d3.selectAll('.single-node').style('opacity', 1)
                  d3.selectAll('.single-line').style('opacity', 1)
                  d3.selectAll('.link-text').style('opacity', 1)
                  _this.info = ''
                })
    
              link
                .on('mouseover', function (d) {
                  d3.selectAll('.single-node').style('opacity', 0.2)
                  d3.selectAll('.single-line').style('opacity', 0.2)
                  d3.selectAll('.link-text').style('opacity', 0.2)
                  d3.select('#single-line' + d.id).style('opacity', 1)
                  d3.select('#link-text' + d.id).style('opacity', 1)
                  d3.select('#single-node' + d.source.id).style('opacity', 1)
                  d3.select('#single-node' + d.target.id).style('opacity', 1)
                  _this.info = JSON.stringify(d)
                })
                .on('mouseout', function () {
                  d3.selectAll('.single-node').style('opacity', 1)
                  d3.selectAll('.single-line').style('opacity', 1)
                  d3.selectAll('.link-text').style('opacity', 1)
                  _this.info = ''
                })
            }
          })
    
          /**
           * @name: 设置节点颜色
           * @param {*} node
           */
          function nodeColor(node) {
            const type = node.semantic_type
            if (_this.typeColor[type]) {
              return _this.typeColor[type]
            } else {
              return '#ddd'
            }
          }
    
          /**
           * @name: 新增节点和关系
           * @param {*} node
           */
          function addNodesAndLinks(node) {
            // 模拟接口返回节点和关系数据
            _this.$nextTick(() => {
              const res = mock
              const resData = res.data.relations
              const edgeResult = []
              for (let i = 0; i < resData.length; i++) {
                edgeResult[i] = {
                  id: resData[i].id,
                  source: resData[i].direction === 0 ? node.id : resData[i].relation_node.id,
                  target: resData[i].direction === 0 ? resData[i].relation_node.id : node.id,
                  relation: resData[i].name,
                  name: resData[i].name,
                  properties: resData[i].properties,
                  semantic_type: resData[i].semantic_type
                }
              }
              const nodeReault = resData.map(_ => _.relation_node)
              nodeReault.forEach((item) => {
                _this.nodes.push(item)
              })
              _this.nodes.push({
                'id': 'qwertyuiop',
                'name': '测试无关系节点',
                'semantic_type': 'Symptom',
                'labels': ['Concept', 'Symptom'],
                'properties': {
                  'scenes': 'allinmd',
                  'status': 1,
                  'lastModified': 1618293198,
                  'releaseDate': 1618293198
                }
              })
              edgeResult.forEach((item) => {
                _this.links.push(item)
              })
              updateObj.update({
                nodes: _this.nodes,
                links: _this.links
              })
            })
          }
    
          /**
           * @name: 关联节点去重重组
           * @param {*} objarray
           */
          function uniqObjInArray(objarray) {
            const len = objarray.length
            const tempJson = {}
            const res = []
            for (let i = 0; i < len; i++) {
              // 取出每一个对象
              tempJson[JSON.stringify(objarray[i])] = true
            }
            const keyItems = Object.keys(tempJson)
            for (let j = 0; j < keyItems.length; j++) {
              res.push(JSON.parse(keyItems[j]))
            }
            return res
          }
    
          /**
           * @name: 收起,删除当前节点下一级没有其他关系的节点
           * @param {*} node
           */
          function deleteNextNodes(node) {
            const relationNode = []
            const relationList = []
            const hasRelationList = []
            d3.selectAll('.single-line').each(function (e) {
              if (e.source.id === node.id) {
                hasRelationList.push(e)
              } else {
                relationList.push(e) // 删除节点有关系的其他关系
              }
              // 需要删除的节点相关的节点
              if (e.source.id === node.id) {
                relationNode.push(e.target)
              }
              if (e.target.id === node.id) {
                relationNode.push(e.source)
              }
            })
            let tempNodeList = JSON.parse(JSON.stringify(relationNode))
            tempNodeList = uniqObjInArray(tempNodeList)
            // 区分下级节点是否是孤节点,如果还有其他关系,则不能删除
            tempNodeList.forEach(function (item) {
              const hasLine = relationList.findIndex(jtem => jtem.target.id === item.id || jtem.source.id === item.id)
              if (hasLine >= 0) {
                item.notSingle = true
              }
            })
            tempNodeList.forEach(function (item) {
              if (!item.notSingle) {
                d3.select('#single-node' + item.id).remove()
              }
            })
            const otherTempNode = []
            tempNodeList = tempNodeList.map(item => {
              if (!item.notSingle) {
                otherTempNode.push(item)
              }
            })
            hasRelationList.forEach(item => {
              otherTempNode.forEach(jtem => {
                if (jtem.id === item.source.id || jtem.id === item.target.id) {
                  d3.select('#single-line' + item.id).remove()
                  d3.select('#link-text' + item.id).remove()
                }
              })
            })
            d3.select('.menu-circle').remove()
          }
    
          /**
           * @name: 隐藏,删除当前及下一级没有其他关系的节点
           * @param {*} node
           */
          function deleteNodeAndLinks(node) {
            const removeIndex = _this.nodes.findIndex(data => data.id === node.id)
            _this.nodes.splice(removeIndex, 1)
            const relationNode = []
            const relationList = []
            const clickNode = node.id
            d3.selectAll('.single-line').each(function (e) {
              if (e.source.id === node.id || e.target.id === node.id) {
                d3.select(this).remove()
              } else {
                relationList.push(e)
              }
              // 需要删除的节点相关的节点
              if (e.source.id === node.id) {
                relationNode.push(e.target)
              }
            })
            let tempNodeList = JSON.parse(JSON.stringify(relationNode))
            tempNodeList = uniqObjInArray(tempNodeList)
            // 区分下级节点是否是孤节点
            tempNodeList.forEach(function (item) {
              const hasLine = relationList.findIndex(jtem => jtem.target.id === item.id || jtem.source.id === item.id)
              if (hasLine >= 0) {
                item.notSingle = true
              }
            })
            tempNodeList.forEach(function (item) {
              if (!item.notSingle) {
                d3.select('#single-node' + item.id).remove()
              }
            })
            d3.selectAll('.single-node').each(function (d) {
              const temp = d.id
              // 删除当前需要隐藏的节点
              if (temp === clickNode) {
                d3.select('.menu-circle').remove()
                d3.select(this).remove()
              }
            })
            d3.selectAll('.link-text').each(function (e) {
              if (e.source === node || e.target === node) {
                d3.select(this).remove()
              }
            })
          }
    
          /**
           * @name: 生成操作菜单
           * @param {*} current 当前元素
           * @param {*} d 当前元素对应的数据
           * @param {*} flag 显隐
           */
          function toggleMenu(current, d, flag) {
            const currentD = d
            const data = [{
              population: 30,
              value: '隐藏',
              type: 'delete'
            }, {
              population: 30,
              value: '收起',
              type: 'showOn'
            }, {
              population: 30,
              value: '展开',
              type: 'showOff'
            }]
            // 创建一个环生成器
            const arc = d3.arc()
              .innerRadius(80) // 内半径
              .outerRadius(35) // 外半径
            const pie = d3.pie()
              .value(function (d) {
                return d.population
              })
              .sort(null)
            const pieData = pie(data)
            const pieAngle = pieData.map(function (p) {
              return (p.startAngle + p.endAngle) / 2 / Math.PI * 180
            })
            // 菜单容器
            const g = current
              .append('g')
              .attr('class', 'menu-circle')
              .attr('width', 100)
              .attr('height', 100)
            const Pie = g.append('g')
            Pie.selectAll('path')
              .data(pie(data))
              .enter()
              .append('path')
              .attr('d', arc)
              .attr('fill', '#d3d7dc')
              .style('stroke', '#fff')
              .style('cursor', 'pointer')
              .on('click', function (d) {
                if (d.data.type === 'delete') {
                  deleteNodeAndLinks(currentD)
                } else if (d.data.type === 'showOn') {
                  deleteNextNodes(currentD)
                } else {
                  addNodesAndLinks(currentD)
                }
                d3.event.stopPropagation()
              })
              .on('mouseover', function () {
                d3.select(this)
                  .style('fill', '#d3d7dc')
                  .transition()
                  .style('fill', '#aaaeb4')
              })
              .on('mouseout', function () {
                d3.select(this)
                  .style('fill', '#aaaeb4')
                  .transition()
                  .style('fill', '#d3d7dc')
              })
    
            // 安妮文字
            const labelFontSize = 12
            const labelValRadius = (170 * 0.35 - labelFontSize * 0.35)
            const labelValRadius1 = (170 * 0.35 + labelFontSize * 0.35)
            const labelsVals = current
              .select('.menu-circle')
              .append('g')
              .classed('labelsvals', true)
            // 定义两条路径以使标签的方向正确
            labelsVals.append('def')
              .append('path')
              .attr('id', 'label-path-1')
              .attr('d', `m0 ${-labelValRadius} a${labelValRadius} ${labelValRadius} 0 1,1 -0.01 0`)
            labelsVals.append('def')
              .append('path')
              .attr('id', 'label-path-2')
              .attr('d', `m0 ${-labelValRadius1} a${labelValRadius1} ${labelValRadius1} 0 1,0 0.01 0`)
            labelsVals.selectAll('text')
              .data(data)
              .enter()
              .append('text')
              .attr('dy', function (d) {
                if (d.type === 'showOn') {
                  return -5
                } else {
                  return 5
                }
              })
              .style('font-size', labelFontSize)
              .style('fill', 'black')
              .style('font-weight', 'bold')
              .style('text-anchor', 'middle')
              .append('textPath')
              .style('cursor', 'pointer')
              .attr('href', function (d, i) {
                const angle = pieAngle[i]
                if (angle > 90 && angle <= 270) { // 根据角度选择路径
                  return '#label-path-2'
                } else {
                  return '#label-path-1'
                }
              })
              .attr('startOffset', function (d, i) {
                const p = pieData[i]
                const angle = pieAngle[i]
                const percent = (p.startAngle + p.endAngle) / 2 / 2 / Math.PI * 100
                if (angle > 90 && angle <= 270) { // 分别计算每条路径的正确百分比
                  return 100 - percent + '%'
                }
                return percent + '%'
              })
              .text(function (d) {
                return d.value
              })
              .on('click', function (d) {
                if (d.type === 'delete') {
                  deleteNodeAndLinks(currentD)
                } else if (d.type === 'showOn') {
                  deleteNextNodes(currentD)
                } else {
                  addNodesAndLinks(currentD)
                }
                d3.event.stopPropagation()
              }, true)
            if (flag === false) {
              d3.selectAll('.menu-circle').remove()
            }
          }
    
          /**
           * @name: 节点文字换行
           * @param {*} dom
           * @param {*} data
           * @param {*} breaking 是否换行
           */
          function textBreaking(dom, data, breaking) {
            const text = data.name
            if (breaking) {
              const len = text.length
              if (len <= 3) {
                dom.append('tspan')
                  .attr('x', 0)
                  .attr('y', 0)
                  .text(text)
              } else {
                const topText = text.substring(0, 3)
                const midText = text.substring(3, 7)
                let botText = text.substring(7, len)
                let topY = -22
                let midY = 8
                const botY = 34
                if (len <= 9) {
                  topY += 10
                  midY += 10
                } else {
                  botText = text.substring(7, 9) + '...'
                }
                dom.text('')
                dom.append('tspan')
                  .attr('x', 0)
                  .attr('y', topY)
                  .text(function () {
                    return topText
                  })
                dom.append('tspan')
                  .attr('x', 0)
                  .attr('y', midY)
                  .text(function () {
                    return midText
                  })
                dom.append('tspan')
                  .attr('x', 0)
                  .attr('y', botY - 7)
                  .text(function () {
                    return botText
                  })
              }
            } else {
              dom.append('tspan')
                .attr('x', 0)
                .attr('y', 0)
                .style('font-size', 12)
                .style('stroke', '#333')
                .text(data.name)
            }
          }
    
          /**
            * @name: 拖动
            * @param {*} event
            */
          function dragstarted(event) {
            if (!d3.event.active) {
              simulation.alphaTarget(0.8).restart() // 设置衰减系数,对节点位置移动过程的模拟,数值越高移动越快,数值范围[0, 1]
            }
            event.fx = event.x
            event.fy = event.y
          }
          function dragged(event) {
            event.fx = d3.event.x
            event.fy = d3.event.y
          }
          function dragended(event) {
            if (!d3.event.active) {
              simulation.alphaTarget(0)
            }
            event.fx = null
            event.fy = null
          }
    
          // updateObj.update({
          //   nodes: _this.nodes,
          //   links: _this.links
          // })
    
          // 模拟接口返回节点信息
          _this.$nextTick(() => {
            // 初次返回单个节点
            const res = {
              'code': 0,
              'message': '',
              'data': {
                'id': '83c8aeb69c1011eb892ad31672d12132',
                'name': '骨筋膜室综合症',
                'semantic_type': 'Disease',
                'labels': ['Concept', 'Disease'],
                'properties': {
                  'scenes': 'allinmd',
                  'status': 1,
                  'lastModified': 1618293198,
                  'releaseDate': 1618293198
                }
              }
            }
            const data = res.data
            _this.nodes.push(data)
            updateObj.update({
              nodes: _this.nodes,
              links: _this.links
            })
          })
        }
      }
    }
    </script>
    
    <style>
    .d3-container {
      position: relative;
    }
    .d3-container .info {
      background: #fff;
      position: absolute;
      left: 50px;
      bottom: 50px;
      z-index: 9;
    }
    .d3-container .btns {
      background: #fff;
      position: absolute;
      right: 50px;
      bottom: 200px;
      z-index: 99;
    }
    .d3-container .btns span {
      cursor: pointer;
    }
    .d3-container .types {
      position: absolute;
      left: 50px;
      top: 50px;
      z-index: 9;
    }
    .d3-container .types span {
      display: inline-block;
      background: #a5abb6;
      border-radius: 4px;
      margin-right: 10px;
      padding: 5px 6px;
      cursor: pointer;
      color: #2e0f00;
      font-size: 12px;
    }
    </style>
    
    

    mock.json

    {
      "code": 0,
      "message": "",
      "data": {
        "relations": [{
          "id": "2730",
          "name": "composed_of",
          "semantic_type": "composed_of",
          "properties": {
            "scenes": "allinmd",
            "status": 1,
            "lastModified": 1618832915,
            "releaseDate": 1618832915
          },
          "direction": 0,
          "relation_node": {
            "id": "2c29f5249cf211ebbc710242c0a8c409",
            "name": "外伤史",
            "semantic_type": "Symptom",
            "labels": ["Concept", "Symptom"],
            "properties": {
              "scenes": "allinmd",
              "status": 1,
              "lastModified": 1618384950,
              "releaseDate": 1618384950
            }
          }
        }, {
          "id": "2677",
          "name": "composed_of",
          "semantic_type": "composed_of",
          "properties": {
            "scenes": "allinmd",
            "status": 1,
            "lastModified": 1618803809,
            "releaseDate": 1618803809
          },
          "direction": 1,
          "relation_node": {
            "id": "8f2d01129c1011eb892ad31672d12132",
            "name": "膝关节外伤及手术史",
            "semantic_type": "Symptom",
            "labels": ["Concept", "Symptom"],
            "properties": {
              "scenes": "allinmd",
              "status": 1,
              "lastModified": 1618293198,
              "releaseDate": 1618293198
            }
          }
        }, {
          "id": "2649",
          "name": "relation",
          "semantic_type": "relation",
          "properties": {
            "scenes": "allinmd",
            "status": 1,
            "lastModified": 1618885401,
            "releaseDate": 1618885401
          },
          "direction": 1,
          "relation_node": {
            "id": "8e8922369c1011eb892ad31672d12132",
            "name": "髌骨肌腱炎",
            "semantic_type": "BodyStructure",
            "labels": ["Concept", "Disease"],
            "properties": {
              "scenes": "allinmd",
              "status": 1,
              "lastModified": 1618293198,
              "releaseDate": 1618293198
            }
          }
        }, {
          "id": "2672",
          "name": "relation",
          "semantic_type": "relation",
          "properties": {
            "scenes": "allinmd",
            "status": 1,
            "lastModified": 1618885282,
            "releaseDate": 1618885282
          },
          "direction": 1,
          "relation_node": {
            "id": "8f0c21689c1011eb892ad31672d12132",
            "name": "膝关节脱位",
            "semantic_type": "Disease",
            "labels": ["Concept", "Disease"],
            "properties": {
              "scenes": "allinmd",
              "status": 1,
              "lastModified": 1618293198,
              "releaseDate": 1618293198
            }
          }
        }, {
          "id": "2662",
          "name": "relation",
          "semantic_type": "relation",
          "properties": {
            "scenes": "allinmd",
            "status": 1,
            "lastModified": 1618885172,
            "releaseDate": 1618885172
          },
          "direction": 1,
          "relation_node": {
            "id": "8eec11d49c1011eb892ad31672d12132",
            "name": "股骨髁骨折",
            "semantic_type": "Side",
            "labels": ["Concept", "Disease"],
            "properties": {
              "scenes": "allinmd",
              "status": 1,
              "lastModified": 1618293198,
              "releaseDate": 1618293198
            }
          }
        }, {
          "id": "2660",
          "name": "relation",
          "semantic_type": "relation",
          "properties": {
            "scenes": "allinmd",
            "status": 1,
            "lastModified": 1618885118,
            "releaseDate": 1618885118
          },
          "direction": 1,
          "relation_node": {
            "id": "8ed52bcc9c1011eb892ad31672d12132",
            "name": "膝关节内侧副韧带损伤",
            "semantic_type": "Disease",
            "labels": ["Concept", "Disease"],
            "properties": {
              "scenes": "allinmd",
              "status": 1,
              "lastModified": 1618293198,
              "releaseDate": 1618293198
            }
          }
        }, {
          "id": "2636",
          "name": "relation",
          "semantic_type": "relation",
          "properties": {
            "scenes": "allinmd",
            "status": 1,
            "lastModified": 1618884966,
            "releaseDate": 1618884966
          },
          "direction": 1,
          "relation_node": {
            "id": "8ebdb2d09c1011eb892ad31672d12132",
            "name": "膝髌韧带裂(扭)伤",
            "semantic_type": "Disease",
            "labels": ["Concept", "Disease"],
            "properties": {
              "scenes": "allinmd",
              "status": 1,
              "lastModified": 1618293198,
              "releaseDate": 1618293198
            }
          }
        }, {
          "id": "2621",
          "name": "relation",
          "semantic_type": "relation",
          "properties": {
            "scenes": "allinmd",
            "status": 1,
            "lastModified": 1618883252,
            "releaseDate": 1618883252
          },
          "direction": 1,
          "relation_node": {
            "id": "84417f449c1011eb892ad31672d12132",
            "name": "剥脱性骨软骨炎",
            "semantic_type": "Disease",
            "labels": ["Concept", "Disease"],
            "properties": {
              "scenes": "allinmd",
              "status": 1,
              "lastModified": 1618293198,
              "releaseDate": 1618293198
            }
          }
        }, {
          "id": "2553",
          "name": "relation",
          "semantic_type": "relation",
          "properties": {
            "scenes": "allinmd",
            "status": 1,
            "lastModified": 1618886711,
            "releaseDate": 1618886711
          },
          "direction": 1,
          "relation_node": {
            "id": "8ef701fc9c1011eb892ad31672d12132",
            "name": "髌骨脱位",
            "semantic_type": "BetterAndWorse",
            "labels": ["Concept", "Disease"],
            "properties": {
              "scenes": "allinmd",
              "status": 1,
              "lastModified": 1618293198,
              "releaseDate": 1618293198
            }
          }
        }, {
          "id": "2538",
          "name": "relation",
          "semantic_type": "relation",
          "properties": {
            "scenes": "allinmd",
            "status": 1,
            "lastModified": 1618886139,
            "releaseDate": 1618886139
          },
          "direction": 1,
          "relation_node": {
            "id": "8edf38889c1011eb892ad31672d12132",
            "name": "膝关节游离体",
            "semantic_type": "Disease",
            "labels": ["Concept", "Disease"],
            "properties": {
              "scenes": "allinmd",
              "status": 1,
              "lastModified": 1618293198,
              "releaseDate": 1618293198
            }
          }
        }, {
          "id": "2531",
          "name": "relation",
          "semantic_type": "relation",
          "properties": {
            "scenes": "allinmd",
            "status": 1,
            "lastModified": 1618886026,
            "releaseDate": 1618886026
          },
          "direction": 1,
          "relation_node": {
            "id": "8eb96dc49c1011eb892ad31672d12132",
            "name": "髌骨软骨软化",
            "semantic_type": "Relieve",
            "labels": ["Concept", "Disease"],
            "properties": {
              "scenes": "allinmd",
              "status": 1,
              "lastModified": 1618293198,
              "releaseDate": 1618293198
            }
          }
        }, {
          "id": "2527",
          "name": "relation",
          "semantic_type": "relation",
          "properties": {
            "scenes": "allinmd",
            "status": 1,
            "lastModified": 1618885900,
            "releaseDate": 1618885900
          },
          "direction": 1,
          "relation_node": {
            "id": "84254cac9c1011eb892ad31672d12132",
            "name": "半月板囊肿",
            "semantic_type": "Disease",
            "labels": ["Concept", "Disease"],
            "properties": {
              "scenes": "allinmd",
              "status": 1,
              "lastModified": 1618293198,
              "releaseDate": 1618293198
            }
          }
        }, {
          "id": "2582",
          "name": "relation",
          "semantic_type": "relation",
          "properties": {
            "scenes": "allinmd",
            "status": 1,
            "lastModified": 1618803809,
            "releaseDate": 1618803809
          },
          "direction": 1,
          "relation_node": {
            "id": "8ed7c3509c1011eb892ad31672d12132",
            "name": "闭合型胫骨平台骨折",
            "semantic_type": "Disease",
            "labels": ["Concept", "Disease"],
            "properties": {
              "scenes": "allinmd",
              "status": 1,
              "lastModified": 1618293198,
              "releaseDate": 1618293198
            }
          }
        }, {
          "id": "2552",
          "name": "relation",
          "semantic_type": "relation",
          "properties": {
            "scenes": "allinmd",
            "status": 1,
            "lastModified": 1618803809,
            "releaseDate": 1618803809
          },
          "direction": 1,
          "relation_node": {
            "id": "8401f0d69c1011eb892ad31672d12132",
            "name": "半月板损伤",
            "semantic_type": "Disease",
            "labels": ["Concept", "Disease"],
            "properties": {
              "scenes": "allinmd",
              "status": 1,
              "lastModified": 1618293198,
              "releaseDate": 1618293198
            }
          }
        }, {
          "id": "5534",
          "name": "relation",
          "semantic_type": "relation",
          "properties": {
            "scenes": "allinmd",
            "status": 1,
            "lastModified": 1618882945,
            "releaseDate": 1618882945
          },
          "direction": 1,
          "relation_node": {
            "id": "8ee67ed69c1011eb892ad31672d12132",
            "name": "髌骨骨折",
            "semantic_type": "Action",
            "labels": ["Concept", "Disease"],
            "properties": {
              "scenes": "allinmd",
              "status": 1,
              "lastModified": 1618293198,
              "releaseDate": 1618293198
            }
          }
        }, {
          "id": "2533",
          "name": "relation",
          "semantic_type": "relation",
          "properties": {
            "scenes": "allinmd",
            "status": 1,
            "lastModified": 1618886473,
            "releaseDate": 1618886473
          },
          "direction": 1,
          "relation_node": {
            "id": "8ee6f92e9c1011eb892ad31672d12132",
            "name": "膝关节或韧带的脱位、劳损或扭伤",
            "semantic_type": "Disease",
            "labels": ["Concept", "Disease"],
            "properties": {
              "scenes": "allinmd",
              "status": 1,
              "lastModified": 1618293198,
              "releaseDate": 1618293198
            }
          }
        }]
      }
    }
    
    展开全文
  • 分析企业自身的主要数据,企业企业企业与个人、个人与个人之间的关系数据,建设企业的关联关系图谱,识别对公客户的关联关系,并找出关联关系中的风险点。 代码说明 以下代码将是我GitHub中的其中一个页面,...
  • 博客地址:...由于发现在我的博客通过点击GitHub链接,会跳转到别人盗用的下载地址,而且还是VIP收费,所以自己把代码上传CSDN资源上。 【因为缺分,所以收5个积分,免费可以到Github上下载最新的代码】
  • Neo4j+springboot+vue+d3.js知识图谱构建和可视化
  • 知识图谱和图分析与可视化

    千次阅读 2019-12-16 17:42:56
    来源:知链数据“知识图谱和图分析与可视化”这个题目看起来比较大,我尝试基于本人的一些图数据可视化与分析经验,对知识图谱和图分析与可视化之间的关系进行简单梳理,并分享一些以知识图谱为代表的...
  • 尤其在金融领域,KGB知识图谱能够实现数据可视化,智能搜索,为金融行业评估风险提供底层性支撑作用。 对于金融企业来说,金融行业中在对借贷资格,反欺诈等行为进行评估时,其审核过程和审核数据都是极其繁琐的。...
  • 大数据被应用到更多领域,已经成为社会发展的重要推动力。通过对CNKI和CSSCI数 据库中大数据领域文献的计量研究,对文献分布特征、研究领域、机构与著者等外部特征进行统计描 述;利用CiteSpace和VosViewer对高被引...
  • 前段时间做了一个关于大数据可视化的项目,用到了d3.js,不得不说,对于大数据的展示,d3真是做到了极致,话不多说,直接上代码。先从最简单的数据展示开始,每天逐步更新。 &lt;!DOCTYPE html&gt; &...
  • 使用开源报表可视化工具Grafana实时监控时序知识图谱数据仓库AbutionGraph中的数据,实时性报表查询, 满足单次百万千万级的数据查询,毫秒级查询延迟,亚秒级对千亿数据量汇总统计,每日过亿报表查询/多维分析/日志...
  • 如今市面上的CRM普遍以机械式的记录和归纳为主,没有一款真正实现智能化的CRM...想象一下,如果我们使用了融合类神经网络、工作图谱、大数据、类人工智能和内容可视化等理念的CRM,那么,我们的工作会变成什么样子?
  • 近年来,随着人工智能、云计算、5G等技术的兴起,也让网络攻击...交互式数据图谱是以可视化方式呈现企业安全状态,它使决策者能够从整体上把控网络安全状态并作出明智的决策,它允许安全分析人员能够快速分析、理解和
  • 云计算、网格计算等关键词代表了当前该领域的热点,网格计算、云计算、分布式计算、网络服务、协同过滤等关键词则代表了当前该领域的前沿,且已经广泛渗透、融合到生物学、病理学、气候学、教育学、企业信息系统、...
  • 基于neo4j的图数据可视化 二维、三维基于样例数据的展示。包含路径查询,节点查找等 视频内容,可到B站观看 https://space.bilibili.com/99795794?from=search&seid=16610440168536806552
  • 关注嘉为科技,获取运维新知数据爆炸式的增长,给信息传播带来了更多的挑战。渐渐地,易于阅读的视觉化内容正在被越来越...在企业IT运维领域,通过运维可视化能将整个运维过程中,关键环节和重要环节的大量数据信息...
  • 关键词:基于行为的学习,基于知识的学习,商业智能,工业4.0,知识图谱,企业图谱, 图数据库, 图计算引擎, 数据可视化应用场景:征信、风控、问答、医疗、能源、舆情、反欺诈、市场营销、社...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,486
精华内容 1,794
关键字:

企业图谱可视化