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:3000orhttp://<your_server_ip>:3000