Advertisement

3D知识图谱可视化

阅读量:

本篇文章介绍了使用3D技术进行大规模知识图谱可视化的优势及其开发过程。尽管面临DOM操作低效和性能问题的挑战(如节点数较多时导致浏览器卡死),通过对比2D与3D技术发现3D渲染更适合展示大规模数据。文章详细说明了安装所需库(如3d-force-graph)并展示了基本的初始化流程和效果展示,并提供了完整的个人开发参考链接以供进一步学习与拓展。

摘要
这篇文章主要讨论了如何利用3D技术优化大规模知识图谱的可视化展示,并解决了传统2D方法在性能上的不足问题。通过对比分析发现,在处理大量节点时采用3D渲染可以显著提升用户体验和效率,并提供了详细的开发步骤和参考资料供读者实践与扩展。

总结
尽管在处理1000多个节点时遇到了挑战,但通过采用3D技术和相关库的支持最终实现了高效的可视化展示效果。

以上为150字左右的核心摘要内容。

目录

  • 一、参考代码

    • 1. Github参考
    • 2. Demo参考
  • 二、为什么使用3D做图谱可视化

    • 1. 背景
    • 2. 使用D3绘制的问题
    • 2. 2D和3D渲染的对比(D3 vs Three)
  • 三、代码实现

    • 1. 安装第三方模块
    • 2. 具体代码
      • 库的导入
      • 初始化
  • 四、效果展示

  • 五、个人代码参考

  • 六、总结

一、参考代码

1. Github参考

  • Three-Force Graph
  • D3 Force 3D
  • 3D Force Graph

2. Demo参考

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

在这里插入图片描述

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

1. 背景

该系统通常由节点和关系两类数据构成,在进行二维可视化展示的过程中:这一过程涉及将复杂的知识结构转化为直观的图表形式。

  • 基于Neo4j提取数据构建知识图谱可视化界面,并采用D3.js库进行动态展示
  • 通过Vue框架与D3v6结合技术开发出动态交互式知识图谱可视化系统

主要采用SVG技术进行图形绘制。而在此场景下,每个节点、关系以及文本信息均对应一个DOM元素。当知识图谱的规模达到数千甚至上万级别时,则会因DOM操作的低效性而导致性能问题的出现。此时建议采取相应的优化措施以减少DOM操作次数。

本文简要探讨操作DOM对其性能参数的作用。其中参数设置可能直接影响或通过中间机制间接影响渲染引擎的工作流程。在实际应用中,网页浏览器通常将功能划分为两个主要部分:一是渲染引擎 ,负责处理页面显示;二是JavaScript执行环境(即JS引擎),负责运行脚本代码。本文不做深入讨论这部分的具体实现细节。

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

  • layout 也就是指当布局发生变化时会触发重新计算资源分配(占用处理器资源,并且可能会占用大量内存)。
  • paint 则是指通过调用浏览器的UI渲染引擎来展示页面内容(主要消耗处理器资源,并且也会占用大量内存)。

在展示大规模知识图谱方面,在现有条件下和资源限制下,该方法可以通过3D技术实现,并通过优化空间布局策略来最大化有限区域内的节点数量。

2. 使用D3绘制的问题

例如,在之前采用 [Vue+d3v6达成动态知识图谱可视化展示] 的方案存在明显的性能问题,并且该代码需详细展示其运行机制。

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

基于本人构建的外贸企业图谱作为案例研究对象,在Neo4j Desktop中提取体积为3.7MB的JSON数据文件信息如下:

  • 节点个数:238
  • 关系个数:4908
在这里插入图片描述

可以看到有近20万行的JSON数据,如果加载该JSON,就会导致浏览器卡死。

此时有几种优化思路:

对JSON文件进行压缩处理 * 其中一个常见操作是删除其properties属性

在2D图形显示方面,在于采用Canvas技术替代传统的SVG渲染方式

  • 使用3D渲染
    • 缺点同上,因为3D也是Canvas
    • 优点:适合大规模的图谱展示场景

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

借助浏览器调试工具性能指标分析,在分别采用2D与3D初始化页面的情况下可观察到两者的执行细节对比。

d3 做2d渲染(80节点和241关系)

在这里插入图片描述

THREE 做3d渲染(300节点和300关系)

在这里插入图片描述

首先需要指出的是,在CPU和GPU的应用及其占用率方面而言,三维渲染的表现确实优于二维渲染(Rendering/Painting/Idle)。然而,在时间效率角度来看,在几百个节点的情况下就已经能够体现出明显的差距(Rendering/Painting/Idle),而当节点数量达到上万时,则会更加显著地显现出来(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()
    }

其中解析(与二维代码一致)以及渲染的函数如下:

复制代码
    /*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实现动态知识图谱可视化展示 一文之中[),其中包含两个主要模块:二维与三维图谱展示两大模块[)。可参考上述链接获取完整代码[),个人水平有限[),仅供学习参考[)。如需进一步扩展,请参考官方GitHub仓库

Github官方下载页面访问此页面获取代码资源:https://github.com/CoderWanp/vue-d3-graph

六、总结

原本打算对大规模样本进行分析研究的计划因技术限制难以实现。经过初步尝试后发现系统运行效率急剧下降,因此决定暂缓推进后续工作以规避潜在问题。


本人博客即将结束,并不会再继续更新内容了。目前来看Web3D的实际应用案例相对较少,在未来如果有新的技术出现可能会考虑采用。

全部评论 (0)

还没有任何评论哟~