2017 年 10 月~2018 年 3 月在南洋理工大学 DMAL 实验室做 RA,参与 Graph Mining 相关项目。这个项目做的是从图/网络里提取一定数量的 pattern,让用户能够方便地构造数据集相关的 query。这个项目的目标有别于别的相关工作:
- pattern 对数据集有尽可能高的覆盖率
- pattern 间冗余度尽可能低
详细描述见导师发的文章 Data-driven Visual Graph Query Interface Construction and Maintenance: Challenges and Opportunities。
到目前为止我已经实现了 pattern 提取的整个过程,接下来要做一些列实验和写论文。无论是实验或作品展示,都需要用户能够操作的 GUI 界面。但是实验室没有啊,怎么办?(其实实验室是有个用 Java Swing 做的半成品,Java 6 年代做的,研究了半天决定放弃)于是做数据挖掘的我又做起了熟悉的前端,前前后后花一个月做了出来。这篇文章介绍用 pattern 拼图的 GUI 界面实现(老板指定名字为 AVATAR
,忘了问缘由)。至于 pattern 提取算法,等文章发出来再做介绍吧。
技术和框架
- 作图库采用 Linkurious.js,它基于 Sigma.js,所以变量名保持为
sigma
,尽管已经 deprecated,但它能正常使用而且提供 Sigma.js 没有的实用功能 - 前端使用了 jQuery,jQuery UI,Font Awesome,Bootstrap v4 等扩展(才发现 Bootstrap v4 正式发布了,从官网学习了新特征,比 v3 用得方便)
- 软件主要是前端的工作,后端比较简单,所以想试试用 Node.js 写后端,使用
Express
框架
功能和实现
上传、加载数据集
用户可以在 Upload datastore
窗口上传固定格式的数据集,让后台生成 pattern。数据集上传后,后台会异步地调用算法程序(C++ 编码)处理数据集,生成 pattern 等信息,通过文件输出等形式让前端跟踪进度。
用户可以在 Load datastore
窗口看到现有数据集和正在处理的数据集和处理的进度,可以加载现有的一个数据集。
我使用 child_process.spwan
接口进行异步调用。上传文件我使用了 connect-busboy
包,实现了以流的方式上传文件。网上的其他上传文件方式(比如 express-fileupload
包)我都尝试过,那些方法不但速度比不上 busboy,而且无法上传 1 GB 左右的大文件(后端会出错,具体消息忘了,大概意思是 memory 不足)。
1 | req.busboy.on('file', (fieldname, file, filename) => { |
程序运行完会生成 GraphInfo.json
,labels.json
,limits.json
,patterns.json
等文件,描述了前端所需要的信息。加载数据集后页面会显示数据集概况和标签。
生成和展示 pattern
加载数据集时候 pattern 已经有了,这一步用户在 Generate patterns
窗口指定数量和边数。
调用选择 pattern 的程序,这一步需要对 pattern 进行冗余选取,多次调用 boost 的图形库函数,尽管使用了多线程,速度也不是特别快,一分钟左右。
1 | app.get('/datastores/:name/patterns', (req, res) => { |
图的分布是 NP 问题,界面的目标是尽可能清晰地展示 pattern 供用户使用,由于时间关系我不能花大量时间在图显示布局方面,对比现成的常用布局算法,我选用了 ForceAtlas2
,Linkurious.js 提供这个布局插件。布局算法过后,我会适当旋转和拉伸点使得 pattern 尽可能地占满显示窗口。
1 | /** |
添删点、边
点击左键添加点和边,点击右键删除点或边。通过监听鼠标事件实现。
此外,右键是删除功能,需要屏蔽浏览器默认的右键菜单:
1 | // ***************************** remove node ***************************** |
选择、拖动图形
组合使用了 Linkurious.js 的 select
,activeState
,dragNodes
插件实现基础功能。其中,同时拖动多个点的时候点的位置经常不准确(估计是插件的 bug),我只好重新计算点的坐标。
1 | s.dragListener.bind('startdrag', function (e) { |
lasso
插件提供了强大的多选工具:
添删标签(label)
标签分组显示,用户选定点后,双击标签给点添加或更改标签;如果想取消标签,选中点后,点击 Detach label
按钮。
添加 pattern
用户可以通过拖动把 pattern 添加到主画板,我使用 jQuery UI Draggable 实现拖动功能。自带的 clone
功能不能拷贝 <canvas>
,所以我自己实现了拷贝 <canvas>
的功能,定义为插件的 helper
函数参数。
1 | /** |
安装
- Install Node.js
- Install Node.js packages via command
npm install
- Start server via command
node app.js
- Access web via
http://localhost:3000
orhttp://<your_server_ip>:3000