漫谈可视化Prefuse(三)---Prefuse API数据结构阅读有感
前篇回顾:上篇《漫谈可视化Prefuse(二)---一分钟学会Prefuse》主要通过一个Prefuse的具体实例了解了构建一个Prefuse application的具体步骤。一个Prefuse Application需要经过数据导入(文本数据、数据库)->Prefuse数据结构接收数据->注册各种效果的Actions->渲染Renderer->交互展现Display的流程。
摸清了Prefuse那些看似眼花缭乱的框架结构,剩下的就是抽丝剥茧,顺藤摸瓜,结合Manual和API掀开Prefuse的神秘面纱。首先从Prefuse的数据结构开始:
1.prefuse.data:该包主要包含了接口:Node(点)、Edge(边)、Tuple(元组)
类:CascadedTable(级联表)、Graph(图)、Schema(模式)、SpanningTree(生成树)、Table(表)、Tree(树)。每个结构都有自己的属性和方法,下面列举了一些接口和类的主要成员:
Edge:
方法:Node getAdjacentNode(Node n)
返回给定节点的相邻节点集合
方法:Graph getGraph()
返回改变所在图形对象graph
方法:Node getSourceNode()/getTargetNode()
返回源节点、目标节点
方法:boolean isDirected()
判断有向图还是无向图 Node:
Graph getGraph()
返回节点所在的图形graph
int getInDegree()
返回节点入度个数
int getOutDegree()
返回节点出度个数
int getDegree()
返回节点度数
java.util.Iterator inEdges()
返回指向该节点的边的迭代器
java.util.Iterator outEdges()
返回从节点指出的边的迭代器
java.util.Iterator edges()
返回边的迭代器
java.util.Iterator inNeighbors()
返回所有链入该节点的迭代器
java.util.Iterator outNeighbors()
Get an iterator over all adjacent nodes connected to this node by an outgoing edge (i.e., all nodes "pointed" to by this one).
返回所有链出该节点的迭代器
java.util.Iterator neighbors()
返回所有近邻节点的迭代器 Node getParent()
返回父节点
Edge getParentEdge()
返回父边
int getDepth()
返回深度(根节点深度为0)
int getChildCount()
返回子节点个数
int getChildIndex(Node child)
返回节点索引值
Node getChild(int idx)
根据序号获得相应节点
Node getFirstChild()
获得第一个子节点
Node getLastChild()
获得最后一个子节点
Node getPreviousSibling()
得到上一个兄弟节点
Node getNextSibling()
得到下一个兄弟节点
java.util.Iterator children()
获得孩子节点的迭代器
java.util.Iterator childEdges()
获得子边集合的迭代器 Tuple:
Schema getSchema()
返回tuple数据概要
Table getTable()
返回tuple所在图表
int getRow()
返回tuple所在行数 Graph:
构造方法:
public Graph()创建一个空的无向图;
public Graph(boolean directed)true为有向,false为无向;
public Graph(Table nodes, Boolean directed)根据给定节点集合创建有向/无向图;
public Graph(Table nodes, boolean directed, java.lang.String nodeKey, java.lang.String sourceKey,java.lang.String targetKey)
nodeKey起到标示作用,如果为null,则默认使用row numbers(行号)
public Graph(Table nodes, Table edges,Boolean directed)
public Graph(Table nodes, Table edges, boolean directed, java.lang.String sourceKey, java.lang.String targetKey)
还有一些常用方法如添加删除节点或边等。 Schema:
Schema类是表示一个表格的列,其属性包括列名、数据类型、默认值。
其构造方法有:
Schema()
Schema(int ncols)
Schema(java.lang.String[] names, java.lang.Class[] types)
Schema(java.lang.String[] names, java.lang.Class[] types, java.lang.Object[] defaults)
主要方法有添加删除列,获取列名,锁定Schema对象等。 Table:
表格是由一系列行和列数组组成的,每一行即为一个数据记录,每一列是由指定数据域和数据类的数据组成。表格的数据可以直接通过使用行数和列名称进行访问。
表格的行可以插入和删除。
Table的构造方法:
Table()
Table(int nrows, int ncols)
protected Table(int nrows, int ncols, java.lang.Class tupleType)
其主要包含添加删除行或列 Tree:
构造方法如下:
Tree()
Tree(Table nodes, Table edges)
Tree(Table nodes, Table edges, java.lang.String sourceKey, java.lang.String targetKey)
Tree(Table nodes, Table edges, java.lang.String nodeKey, java.lang.String sourceKey, java.lang.String targetKey)
其方法主要有获取删除子节点、父节点、根节点
2.prefuse.data下还有一些包如:
prefuse.data.column
该包中主要介绍了列属性中可以有不同类型的列值,如BooleanColumn、DateColumn表示列中存储布尔类型和日期类型的值。列类的抽象基类是AbstractColumn。
prefuse.data.event
该包主要包含一些监听类,比如ColumnListener、ExpressionListener等分别表示针对不同对象的监听。
3.Prefuse还至于一些表达式的应用以及Prefuse对于各类表达式的解析
prefuse.data.expression(表达式)
该包主要包含了Prefuse关于表达式用法的类,有AndPredicate、NotPredicate、OrPredicate、ArithmeticExpression、BinaryExpression等分别表示AndPredicate(与)、OrPredicate(或)、NotPredicate(非)、ArithmeticExpression(算术表达式)、BinaryExpression(二进制表达式)等。
prefuse.data.expression.parser(表达式解析)
该包包含如何解析表达式Expression的类。
Prefuse支持的表达式涵盖很全面:
支持操作符运算、流程控制如:”x+y“(加运算)、"x^y"(平方运算)、”x>y“(比较运算)、”IF test THEN x ELSE
y“(if-then-else流程)等等;
一般常用函数如:"ISNODE()"(判断当前Tuple是否是一个节点)、”DEGREE()“(如果当前Tuple图中节点,返回该节点的度数)、”TREEDEPTH()“(如果当前Tuple是图中节点,则返回该节点在书中的深度)等;
数学运算如:"ABS(x)"(绝对值运算)、”SIN(x)“(正弦运算)、"FLOOR(x)"(向下取整)、”SUM(a,b,c...)“(求和运算)等等;
常用字符串运算如:”CAP(str)“(首字母大写)、”REPEAT(str,count)“(字符串替换操作)、”REVERSE(str)“(反转字符串)等等;
颜色控制函数如:”RGB(r,g,b)“(RGB模式颜色赋值)、”GRAY(v)“(灰度值模式颜色赋值)等;
综上相关表达式的支持,大大增强了Prefuse的灵活性,丰富了Prefuse的一些操作功能。
4.有关包prefuse.data.io以及prefuse.data.io.sql已经在《漫谈可视化Prefuse(一)---从SQL Server数据库读取数据》通过离子阐述过。
但是为了提高用户可操作性,也为了熟悉Java图形编程如何进行界面之间的传值,对上面文章中的例子进行了改进,将部分参数如端口号、数据库用户名、密码等信息开放给用户填写,提高程序的可操作性和灵活性,后期实际开发还会能够让用户在多中数据库之间切换。
我的界面传值思路:首先创建一个接收和读取数据的对象config,在填写参数的界面中画出文本框供用户填写参数,在完成按钮中添加监听事件,将所填信息赋给对象config,并执行在父界面中画出读取数据构成的图形,代码如下:
ConnectionToDB.java
public class ConnectionToDB{
public static Visualization vis = new Visualization();
public static Config config = new Config();//存储、获取参数对象
public static JFrame jf = new JFrame();
//标签显示
public static JLabel nodeLabel = new JLabel("节点查询:");
public static JLabel edgeLabel = new JLabel("边查询:");
public static JLabel strConfigLabel = new JLabel("配置字符串:");
public static JLabel databaseNameLabel = new JLabel("数据库名称:");
public static JLabel usernameLabel = new JLabel("用户名:");
public static JLabel passwordLabel = new JLabel("密码:");
public static JLabel portNumberLabel = new JLabel("端口号:");
//文本框
public static JTextField nodeText = new JTextField();
public static JTextField edgeText = new JTextField();
public static JTextField strConfigText = new JTextField();
public static JTextField databaseNameText = new JTextField();
public static JTextField usernameText = new JTextField();
public static JTextField passwordText = new JTextField();
public static JTextField portNumberText = new JTextField();
/**
* @param args
* @throws DataIOException
*/
public static void main(String[] args) throws DataIOException {
//1.构建显示画面 2.填写参数配置 3.配置传值到主界面 4.主界面图形展示
//-----------1、构建主界面-----------
JMenu dataMenu = new JMenu("数据导入");//添加菜单按钮
final JMenuItem dataItem = new JMenuItem("连接数据库");
dataItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
final JFrame second = new JFrame("second");
second.setSize(400,400);
second.setLayout(null);
strConfigLabel.setBounds(50, 20, 80, 30);
strConfigText.setBounds(130, 20, 150, 30);
second.add(strConfigLabel);
second.add(strConfigText);
databaseNameLabel.setBounds(50, 60, 80, 30);
databaseNameText.setBounds(130, 60, 150, 30);
second.add(databaseNameLabel);
second.add(databaseNameText);
usernameLabel.setBounds(50, 100, 80, 30);
usernameText.setBounds(130, 100, 150, 30);
second.add(usernameLabel);
second.add(usernameText);
passwordLabel.setBounds(50, 140, 80, 30);
passwordText.setBounds(130, 140, 150, 30);
second.add(passwordLabel);
second.add(passwordText);
portNumberLabel.setBounds(50, 180, 80, 30);
portNumberText.setBounds(130, 180, 150, 30);
second.add(portNumberLabel);
second.add(portNumberText);
nodeLabel.setBounds(50, 220, 80, 30);
nodeText.setBounds(130, 220, 150, 30);
second.add(nodeLabel);
second.add(nodeText);
edgeLabel.setBounds(50, 260, 80, 30);
edgeText.setBounds(130, 260, 150, 30);
second.add(edgeLabel);
second.add(edgeText);
JButton ok = new JButton("完成配置");
ok.setBounds(70, 300, 100, 30);
second.add(ok);
second.setVisible(true);
ok.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if(nodeText.getText()!=null && edgeText.getText()!=null){
configPass();
System.out.println("node:"+ config.getNodeSql());
try {
actionEvent();
// second.dispose();这种关闭方式也可以
second.dispatchEvent(new WindowEvent(second,WindowEvent.WINDOW_CLOSING));//关闭子窗口
visual();
} catch (DataIOException e1) {
e1.printStackTrace();
}
}
}
});
}
});
JMenuBar bar = new JMenuBar();
bar.add(dataMenu);
dataMenu.add(dataItem);
jf.setSize(new Dimension(800, 600));
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setJMenuBar(bar);
// jf.pack();
jf.setVisible(true);
}
/**
* 存储配置界面用户输入的值
*/
private static void configPass() {
config.setNodeSql(nodeText.getText());
config.setEdgeSql(edgeText.getText());
config.setStrConfig(strConfigText.getText());
config.setDatabaseName(databaseNameText.getText());
config.setUsername(usernameText.getText());
config.setPassword(passwordText.getText());
config.setPortNumber(portNumberText.getText());
}
/**
* 连接数据库并添加相应效果渲染和动作
* @throws DataIOException
*/
public static void actionEvent() throws DataIOException{
String driver = config.getStrConfig().toString();
String url = "jdbc:sqlserver://localhost:"+config.getPortNumber().toString()+";DatabaseName="+config.getDatabaseName().toString()+"";
String username = config.getUsername().toString();
String password = config.getPassword().toString();
DatabaseDataSource dbds = null;
try {
dbds = ConnectionFactory.getDatabaseConnection(driver, url, username, password);
} catch (SQLException e1) {
e1.printStackTrace();
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
}
System.out.println(config.getEdgeSql());
Table nodes = dbds.getData(config.getNodeSql().toString());
Table edges = dbds.getData(config.getEdgeSql().toString());
Graph graph = new Graph(nodes, edges, false, "id", "sid", "tid");
vis.add("graph", graph);
LabelRenderer label = new LabelRenderer("name");
label.setRoundedCorner(10, 10);
vis.setRendererFactory(new DefaultRendererFactory(label));
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 text = new ColorAction("graph.nodes", VisualItem.TEXTCOLOR, ColorLib.gray(0));
ColorAction edges1 = new ColorAction("graph.edges", VisualItem.STROKECOLOR, ColorLib.gray(200));
ActionList color = new ActionList();
color.add(fill);
color.add(text);
color.add(edges1);
ActionList layout = new ActionList(Activity.INFINITY);
layout.add(new ForceDirectedLayout("graph"));
layout.add(new RepaintAction());
vis.putAction("color", color);
vis.putAction("layout", layout);
}
/**
* 添加控制器,显示图形
*/
public static void visual(){
Display display = new Display(vis);
display.setSize(700, 600);
display.pan(250, 250);
display.addControlListener(new DragControl());
display.addControlListener(new PanControl());
display.addControlListener(new ZoomControl());
display.addControlListener(new WheelZoomControl());
display.addControlListener(new FocusControl(1));
display.addControlListener(new ZoomToFitControl());
jf.add(display);
vis.run("color");
vis.run("layout");
}
}
Config.java:
public class Config {
public String nodeSql;
public String edgeSql;
public String strConfig;
public String databaseName;
public String username;
public String password;
public String portNumber;
public String getStrConfig() {
return strConfig;
}
public void setStrConfig(String strConfig) {
this.strConfig = strConfig;
}
public String getDatabaseName() {
return databaseName;
}
public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPortNumber() {
return portNumber;
}
public void setPortNumber(String portNumber) {
this.portNumber = portNumber;
}
public String getNodeSql() {
return nodeSql;
}
public void setNodeSql(String nodeSql) {
this.nodeSql = nodeSql;
}
public String getEdgeSql() {
return edgeSql;
}
public void setEdgeSql(String edgeSql) {
this.edgeSql = edgeSql;
}
}
具体图形如下:
(1)带有功能菜单的父界面:

(2)参数配置界面:

(3)填写配置参数界面:

(4)图形显示在父界面并关闭配置窗口:

因为之前对于Swing和AWT编程不是很熟悉,考虑在界面传值也可以做,但是对于多个字符串的传值可能逻辑比较复杂,这里采用一个类Config用来封装数据从而完成数据的存储和读取的工作。
本文链接《漫谈可视化Prefuse(三)---Prefuse API数据结构阅读有感》
http://www.cnblogs.com/bigdataZJ/p/VisualizationPrefuse3.html
后续将继续API之路,了解Prefuse使用的套路,先顺着它,依着它,摸清它的脾性后再一举拿下它^_^
友情赞助
如果你觉得博主的文章对你那么一点小帮助,恰巧你又有想打赏博主的小冲动,那么事不宜迟,赶紧扫一扫,小额地赞助下,攒个奶粉钱,也是让博主有动力继续努力,写出更好的文章^^。
1. 支付宝 2. 微信

漫谈可视化Prefuse(三)---Prefuse API数据结构阅读有感的更多相关文章
- 漫谈可视化Prefuse(四)---被玩坏的Prefuse API
这个双12,别人都在抢红包.逛淘宝.上京东,我选择再续我的“漫谈可视化”系列(好了,不装了,其实是郎中羞涩...) 上篇<漫谈可视化Prefuse(三)---Prefuse API数据结构阅读有 ...
- 漫谈可视化Prefuse(五)---一款属于我自己的可视化工具
伴随着前期的基础积累,翻过API,读过一些Demo,总觉得自己已经摸透了Prefuse,小打小闹似乎已经无法满足内心膨胀的自己.还记得儿时看的<武状元苏乞儿>中降龙十八掌最后一张居然是空白 ...
- 漫谈可视化Prefuse(二)---一分钟学会Prefuse
前篇<漫谈可视化Prefuse(一)---从SQL Server数据库读取数据>主要介绍了prefuse如何连接数据库sql server并读取数据进行可视化展现. 回头想想还是应该好好捋 ...
- 漫谈可视化Prefuse(五)
伴随着前期的基础积累,翻过API,读过一些Demo,总觉得自己已经摸透了Prefuse,小打小闹似乎已经无法满足内心膨胀的自己.还记得儿时看的<武状元苏乞儿>中降龙十八掌最后一张居然是空白 ...
- 漫谈可视化Prefuse(六)---改动源码定制边粗细
可视化一路走来,体会很多:博客一路写来,收获颇丰:代码一路码来,思路越来越清晰.终究还是明白了一句古话:纸上得来终觉浅,绝知此事要躬行. 跌跌撞撞整合了个可视化小tool,零零碎碎结交了众多的志同道合 ...
- 漫谈可视化Prefuse(六)
可视化一路走来,体会很多:博客一路写来,收获颇丰:代码一路码来,思路越来越清晰.终究还是明白了一句古话:纸上得来终觉浅,绝知此事要躬行. 跌跌撞撞整合了个可视化小tool,零零碎碎结交了众多的志同道合 ...
- 35 网络相关函数(三)——live555源码阅读(四)网络
35 网络相关函数(三)——live555源码阅读(四)网络 35 网络相关函数(三)——live555源码阅读(四)网络 简介 5)NoReuse不重用地址类 6)initializeWinsock ...
- Vue.js 组件的三个 API:prop、event、slot
组件的构成 一个再复杂的组件,都是由三部分组成的:prop.event.slot,它们构成了 Vue.js 组件的 API.如果你开发的是一个通用组件,那一定要事先设计好这三部分,因为组件一旦发布,后 ...
- Navisworks 提供了.NET, COM和NwCreate 三种API
Navisworks 提供了.NET, COM和NwCreate 三种API.而通常我们说Navisworks API其实指的只是COM或.NET,因为NwCreate的功能比较特殊.待我一一道来: ...
随机推荐
- Ms - Sql 定位附近的人
数据库结构: T_Users longitude decimal(6,0) latitude decimal(6,0) 经纬度:113.284137,23.184625 查出周围2公里以内的人: se ...
- 视频文件写入转换之图像处理-OpenCV应用学习笔记五
在<笔记二>中我们做了视频播放和控制的实现,仅仅算是完成了对视频文件的读取操作:今天我们来一起练习下对视频文件的写入操作:格式转换. 实现功能: 打开一个视频文件play.avi,读取文件 ...
- (转)JQuery上传插件Uploadify使用详解
原文地址:http://www.cnblogs.com/oec2003/archive/2010/01/06/1640027.html Uploadify是JQuery的一个上传插件,实现的效果非常不 ...
- 实现IBatisNet的Dialect分页
Hibernate有其独有的Dialect,对不同的数据库实现sql的分页. 用过MyBatis for Java,它可以拦截SQL语句,通过Interceptor对原始的sql语句进行修改,也就是可 ...
- Linux1:Linux概述
为什么服务器尤其大型服务器都使用Linux系统 服务器尤其是大型服务器一般都使用Linux系统,有以下几点原因: 1.成本低,Linux操作系统是免费的 2.安全性好,Linux采取了许多的安全措施, ...
- 假如现在有一堆长度大于3小于9的电话号码,用座机呼叫,如果出现这样的号码【123和12345】那么12345将永远不会被拨出,因为拨到123的时候电话已经呼出了,试写一个函数输出所有不能被呼出的电话号码(java实现)
解题: 假如现在有一堆长度大于3小于9的电话号码,用座机呼叫,如果出现这样的号码[123和12345]那么12345将永远不会被拨出,因为拨到123的时候电话已经呼出了,试写一个函数输出所有不能被呼出 ...
- Java中文编码小结
Java中文编码小结 1. 只有 字符到字节 或者 字节到字符 的转换才存在编码转码; 2. Java String 采用 UTF-16 编码方式存储所有字符.unicode体系采用唯一的码点表示唯一 ...
- 常用CSS优化总结——网络性能与语法性能建议
在前端面试中最常见的问题就是页面优化和缓存(貌似也是页面优化),被问了几次后心虚的不行,平然平时多少会用到一些,但突然问我,很难把自己知道的都说出来.页面优化明显不是一两句能够说完的,这两天总结了一下 ...
- springmvc下实现登录验证码功能
总体思路,简单讲,就是后台生成图片同时将图片信息保存在session,前端显示图片,输入验证码信息后提交表单到后台,取出存放在session里的验证码信息,与表单提交的验证码信息核对. 点击验证码图片 ...
- [_CN] Eclipse精要与高级开发技术 note
一 eclipse是基于java的 ide ,但根据其体系结构,开发插件,也可拓展到其他语言———————— 尽管如此,但还是很少听说用eclipse来写php或者c的 跨os 三个项目:eclips ...