prefuse是一个非常不错的开源可视化项目,尤其是用在social network/complex network上,个人感觉要比jung好。不过可惜的是,prefuse的user manual还在建设中,并且google resource也少得可怜。好在开源提供了源码,只好看源码了,呵呵。
prefuse user manual上提供了一个简单的例子,这个例子的数据来自一个符合GraphML标准的xml文件(socialnet.xml),大致内容如下:
xml 代码
- <!---->xml version="1.0" encoding="UTF-8"?>
-
- <graphml xmlns="http://graphml.graphdrawing.org/xmlns">
- <graph edgedefault="undirected">
-
-
- <key id="name" for="node" attr.name="name" attr.type="string"/>
- <key id="gender" for="node" attr.name="gender" attr.type="string"/>
-
-
- <node id="1">
- <data key="name">Jeffdata>
- <data key="gender">Mdata>
- node>
- <node id="2">
- <data key="name">Eddata>
- <data key="gender">Mdata>
- node>
- ...........................
- <edge source="1" target="2">edge>
- <edge source="1" target="3">edge>
- ............................
- graph>
- graphml>
大致就是这个样子,程序也比较简单。但是不可能在想要可视化某个社群网络的时候,数据都来自xml,其实大部分还是来自数据库的。prefuse支持从数据库直接获取数据。不过它的user manual上没讲。只好自己探索。
先建立一个在mysql上测试数据库。一个代表节点,一个代表边。
sql 代码
- DROP TABLE IF EXISTS `test`.`node`;
- CREATE TABLE `test`.`node` (
- `id` int(10) unsigned NOT NULL auto_increment,
- `name` varchar(45) NOT NULL,
- `gender` varchar(45) NOT NULL,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
- DROP TABLE IF EXISTS `test`.`edge`;
- CREATE TABLE `test`.`edge` (
- `id` int(10) unsigned NOT NULL auto_increment,
- `sid` int(10) unsigned NOT NULL,
- `tid` int(10) unsigned NOT NULL,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
接下来随便在两个表中插入几条数据,需要注意的是edge表中,sid和tid一定要在node表中存在(即node表中有id与其对应),否则prefuse在读取时会抛出异常。
接下来是程序了:
java 代码
- public class TestMysql {
- public static final String driverName = "com.mysql.jdbc.Driver";
- public static final String dbURL = "jdbc:mysql://localhost:3306/test";
- public static final String userName = "root";
- public static final String userPwd = "123456";
-
- public static void main(String[] args) {
- DatabaseDataSource datasrc = null;
-
- try {
-
- datasrc = ConnectionFactory.getDatabaseConnection(
- driverName, dbURL, userName, userPwd);
-
-
- Table nodes = datasrc.getData("select * from node");
- Table edges = datasrc.getData("select * from edge");
-
- Graph graph = new Graph(nodes, edges, false, "id", "sid", "tid");
-
- Visualization vis = new Visualization();
- vis.add("graph", graph);
-
- LabelRenderer r = new LabelRenderer("name");
- r.setRoundedCorner(8, 8);
- vis.setRendererFactory(new DefaultRendererFactory(r));
-
- int[] palette = new int[] {
- ColorLib.rgb(255,180,180), ColorLib.rgb(190,190,255)
- };
-
- DataColorAction fill = new DataColorAction("graph.nodes", "gender",
- Constants.NOMINAL, VisualItem.FILLCOLOR, palette);
- ColorAction textColor = new ColorAction("graph.nodes",
- VisualItem.TEXTCOLOR, ColorLib.gray(0));
- ColorAction edgesColor = new ColorAction("graph.edges",
- VisualItem.STROKECOLOR, ColorLib.gray(200));
-
- ActionList color = new ActionList();
- color.add(fill);
- color.add(textColor);
- color.add(edgesColor);
-
- ActionList layout = new ActionList(Activity.INFINITY);
- layout.add(new ForceDirectedLayout("graph"));
- layout.add(new RepaintAction());
-
- vis.putAction("color", color);
- vis.putAction("layout", layout);
-
- Display d = new Display(vis);
- d.setSize(720, 500);
- d.addControlListener(new DragControl());
- d.addControlListener(new PanControl());
- d.addControlListener(new ZoomControl());
- d.addControlListener(new NeighborHighlightControl());
-
- JFrame frame = new JFrame("haha");
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- frame.setSize(800, 600);
- frame.add(d);
- frame.setVisible(true);
-
- vis.run("color");
- vis.run("layout");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
第19行:生成一个graph对象,这是可视化的关键。graph对象可以有多种生成方式,光是从数据库生成(也可以说是从table生成,应为prefuse从数据库中取出的都封装成Table)就有好几个方式。不过推荐本例的生成方式,提供的信息越多越可以更精确的描述自己。参数意义分别是:节点的Table,边的Table,是否是有向(true有,false无),节点的主键,边中代表源的列名(与edge表中对应),边中代表目标的列名(与edge表中对应)。
其他的就没得说了,和user manual上差不多。个人认为prefuse的另外一个优点是final类比较少,也就是说可扩展性比较强。例如53-56行添加的动作(在prefuse.controls包),我们就可以随意生成自己的Control。