Github

前端 vue.js + d3.js。

需求

上部区域

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

图像区域

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

下部区域

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

D3.vue

<template><divclass="d3-container"><divclass="types"><spanv-for="(value, key, index) of typeCategories":key="index":style="{backgroundColor: typeColor[key]}"@mouseover="handleTypeMouseover(value, key)"@mouseout="handleTypeMouseout()">{{ key }}({{ value.length }})</span></div><divclass="info">{{ info }}</div><divclass="btns"><spanid="zoomIn">+</span><spanid="zoomOut">-</span><spanid="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].idd3.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.visibleFlagtoggleMenu(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_typeif (_this.typeColor[type]) {return _this.typeColor[type]} else {return '#ddd'}}/*** @name: 新增节点和关系* @param {*} node*/function addNodesAndLinks(node) {// 模拟接口返回节点和关系数据_this.$nextTick(() => {const res = mockconst resData = res.data.relationsconst 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.lengthconst 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.idd3.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 = dconst 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 = 12const 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 * 100if (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.nameif (breaking) {const len = text.lengthif (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 = -22let midY = 8const botY = 34if (len <= 9) {topY += 10midY += 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.xevent.fy = event.y}function dragged(event) {event.fx = d3.event.xevent.fy = d3.event.y}function dragended(event) {if (!d3.event.active) {simulation.alphaTarget(0)}event.fx = nullevent.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}}}]}
}

知识图谱可视化vue.js + d3.js相关推荐

  1. 手把手教你搭建一个中式菜谱知识图谱可视化系统

    手把手教你搭建一个中式菜谱知识图谱可视化系统 中式菜谱知识图谱 1.系统功能 2.先来看看效果 实体间关联关系及实体信息显示 不同类型实体开关显示 搜索功能展示 3.系统实现流程 3.1 数据爬取 3 ...

  2. vue+d3v6实现动态知识图谱可视化展示

    目录 一.前言 二.d3@v6相关链接参考 三.代码详细介绍 1. 页面结构(2021年5月更新) 2. 代码结构(2021年5月新增) 3. 功能及代码介绍 1)d3初始化(2021年5月更新) 2 ...

  3. d3 - 建立力引导图将知识图谱可视化 (一)

    本文要实现的功能与这个网页比较类似: KGBuilder知识图谱可视化 使用到的插件为: d3 没有采用echarts等实现的原因是: echarts比较死板, 有些需求不能实现, 而d3可以灵活的制 ...

  4. 【项目技术点总结之一】vue集成d3.js利用svg加载图片实现缩放拖拽功能

    [项目技术点总结之一]vue集成d3.js利用svg加载图片实现缩放拖拽功能 前言 概述 技术介绍 实现过程 插件安装 引用组件 初始化组件 实现效果 简单理解 使用d3创建一个svg 在svg中提添 ...

  5. 知识图谱可视化技术在美团的实践与探索

    省时查报告-专业.及时.全面的行研报告库 省时查方案-专业.及时.全面的营销策划方案库 [免费下载]2022年3月份热门报告盘点 某短视频APP推荐算法及策略最详细拆解 大萧条来临前的几大征兆 机器学 ...

  6. python知识图谱可视化_知识图谱可视化

    ## 人物关系知识图谱 #### 一.背景 将结构化数据通过关系预处理程序处理为图数据库可以查询的数据,示例是将其中一部分(人物关系数据)可视化表示. #### 二.用到的技术 技术点:图数据库Neo ...

  7. 基于pyecharts的中医药知识图谱可视化

    基于pyecharts的中医药知识图谱可视化 关键词: pyecharts:可视化:中医药知识图谱 摘要: 数据可视化是一种直观展示数据结果和变化情况的方法,可视化有助于知识发现与应用.Neo4j数据 ...

  8. 中医知识图谱可视化创建

    基于pyecharts的中医药知识图谱可视化 关键词: pyecharts:可视化:中医药知识图谱 摘要: 数据可视化是一种直观展示数据结果和变化情况的方法,可视化有助于知识发现与应用.Neo4j数据 ...

  9. 使用Neo4j+InteractiveGraph实现豆瓣电影知识图谱可视化

    0.介绍 本文基于豆瓣电影数据构建了一个电影知识图谱.其中包括电影.演员.导演三种节点及相关关系.并使用InteractiveGraph对图谱完成可视化工作. 数据丰富,图谱包含2.7万个节点,5万条 ...

最新文章

  1. Java for LeetCode 067 Add Binary
  2. Mybatis集成二级缓存与同时使用缓存与事务存在的坑
  3. OpenAI逆炼以文生图:参数缩水2/3性能却更强,还get局部编辑新技能|可试玩
  4. 数据回显---SpringMVC学习笔记(九)
  5. Docker镜像由于代理问题导致不能下载的解决办法
  6. 0-1背包问题(C语言)
  7. Oracle查询笔记
  8. HashMap底层实现原理/HashMap与HashTable区别/HashMap与HashSet区别(转)
  9. python批量操作Linux服务器脚本,ssh密码登录(执行命令、上传、下载)(一)...
  10. matlab宏参赛,MATLAB杯无人机大赛 | 决赛通知!
  11. 素拓活动策划书的撰写范文
  12. 用pathon实现计算器功能
  13. ERP操作手册要不要做?
  14. vue解决分页组件删除和添加内容-页码出现错误
  15. Could not connect to appstore: cURL error 28: Operation timed out after 60000 milliseconds with
  16. 清华大学孙富春教授:基于知识智能的机器人技能学习
  17. Java面试题目分析
  18. inc si指令的作用_亲水作用色谱(HILIC)(二):可选的固定相有哪些?
  19. app Token验证流程
  20. QR分解的三种实现方法

热门文章

  1. navicat导入sql文件成功但没有表
  2. wifi的sta + ap模式
  3. sshpass命令的安装使用
  4. PHP网站漏洞poc,phpyun某处SQL注入漏洞含POC
  5. java.sql.SQLNonTransientConnectionException: Public Key Retrieval is not allowed
  6. 论文:麦克风阵列增强
  7. 【云原生Docker系列第三篇】Docker网络模式(在失去的所有人里,我最怀念自己 )
  8. SpringCould整合oauth2
  9. Memcached快递上手之C#
  10. 快速中值滤波在心电图ECG中的应用