漫談可視化Prefuse(四)---被玩壞的Prefuse API


  這個雙12,別人都在搶紅包、逛淘寶、上京東,我選擇再續我的“漫談可視化”系列(好了,不裝了,其實是郎中羞澀。。。)

 

  上篇《漫談可視化Prefuse(三)---Prefuse API數據結構閱讀有感》主要介紹了可視化工具Prefuse API中主要解讀的是prefuse.data包中的主要接口,並利用《漫談可視化Prefuse(一)---從SQL Server數據庫讀取數據》中例子,將參數配置模塊剝離出來,實現界面傳值,繪制圖形。

 

  本篇決定不再貼API,實在沒啥意思,還占篇幅(但是不容置疑的是API確實很重要,想了解API點這里)。那今天我們主要講講Prefuse比較常用的包以及如何使用這些包做出自己想要的展示效果:

 

  Demo1.解決圖形元素形狀單一化問題——DataShapeAction的使用

  

  Prefuse對於節點的形狀默認是使用Constants.SHAPE_RECTANGLE,這里使用DataShapeAction類完成一個圖形中根據性別不同展示不同的節點形狀,具體代碼如下:

 1 public class Demo1 {
 2 
 3     /**
 4      * @param args
 5      */
 6     public static void main(String[] args) {
 7         
 8         Graph graph = null;
 9         try {
10             graph = new GraphMLReader().readGraph("socialnet.xml");
11         } catch (Exception e) {
12             e.printStackTrace();
13             System.out.println("Error loading");
14             System.exit(1);
15         }
16         
17         Visualization vis = new Visualization();
18         vis.add("graph", graph);        
19         vis.setRendererFactory(new DefaultRendererFactory());
20         
21         int[] palette = new int[]{ColorLib.rgb(255, 180, 180),ColorLib.rgb(190, 190, 255)};
22         DataColorAction fill = new DataColorAction("graph.nodes" , "gender" , Constants.NOMINAL, VisualItem.FILLCOLOR,palette);
23         ColorAction text = new ColorAction("graph.nodes", VisualItem.TEXTCOLOR, ColorLib.gray(0));
24         ColorAction edges = new ColorAction("graph.edges", VisualItem.STROKECOLOR, ColorLib.gray(200));
25         
26         int[] shapes = new int[]{ Constants.SHAPE_RECTANGLE, Constants.SHAPE_DIAMOND};
27         DataShapeAction shape = new DataShapeAction("graph.nodes", "gender", shapes);
28         
29         ActionList color = new ActionList();
30         color.add(fill);
31         color.add(text);
32         color.add(edges);
33         color.add(shape);
34         
35         ActionList layout = new ActionList(Activity.INFINITY);
36         layout.add(new ForceDirectedLayout("graph"));
37         layout.add(new RepaintAction());
38         
39         vis.putAction("color", color);
40         vis.putAction("layout", layout);
41         
42         Display display = new Display(vis);
43         display.setSize(750, 700);
44         display.pan(250, 250);
45         display.addControlListener(new DragControl());
46         display.addControlListener(new PanControl());
47         display.addControlListener(new ZoomControl());
48         display.addControlListener(new WheelZoomControl());
49         display.addControlListener(new FocusControl(1));        
50         display.addControlListener(new ZoomToFitControl());
51 
52         JFrame jf = new JFrame();
53         jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
54         jf.add(display);
55         jf.pack();
56         jf.setVisible(true);
57         
58         vis.run("color");
59         vis.run("layout");
60         
61     }
62 
63 }

  

  DataShapeAction中的第一個參數為指定數據范圍,這里指定針對“graph.nodes”點集;第二個參數為屬性域,這里針對性別不同賦予不同的形狀;第三個參數是形狀數組,這里定義了Constants.SHAPE_RECTANGLE, Constants.SHAPE_DIAMOND,除此之外還有Constants.SHAPE_CROSS、Constants.SHAPE_ELLIPSE、Constants.SHAPE_STAR等。同理prefuse.action.assignment包下的DataColorAction用法與DataShapeAction類似。圖形展示效果如下:

 

 

  Demo2:打破輸入輸出流的壟斷親自繪制圖形——Graph的使用

 

  之前幾篇介紹的例子主要依賴於prefuse.io中的讀入寫出操作類進行數據的導入,這里我們決定甩開膀子,自己豐衣足食,打造自己的圖形,這里主要使用Graph類的添加節點以及添加邊的方法,構建一個互連的三個三角形的形狀。具體代碼如下:

 

 1 public class Demo2{
 2 
 3     public static void main(String[] argv) {
 4         Visualization vis = new Visualization();
 5         Graph g = new Graph();
 6         for(int i = 0; i<3; i++){
 7             Node n1 = g.addNode();
 8             Node n2 = g.addNode();
 9             Node n3 = g.addNode();
10             g.addEdge(n1, n2);
11             g.addEdge(n2, n3);
12             g.addEdge(n3, n1);
13         }
14         g.addEdge(0, 3);
15         g.addEdge(3, 6);
16         g.addEdge(6, 0);
17         
18         vis.add("graph", g);
19         ShapeRenderer renderer = new ShapeRenderer(10);
20         vis.setRendererFactory(new DefaultRendererFactory(renderer));
21         
22         ColorAction nodeFill = new ColorAction("graph.nodes", VisualItem.FILLCOLOR, ColorLib.rgb(10, 150, 220));
23         ColorAction edgesStroke = new ColorAction("graph.edges", VisualItem.STROKECOLOR, ColorLib.rgb(100, 80, 180));
24         ColorAction nodeHighlight = new ColorAction("graph.nodes", VisualItem.HIGHLIGHT, ColorLib.rgb(10, 150, 220));
25         
26         ActionList color = new ActionList();
27         color.add(nodeFill);
28         color.add(edgesStroke);
29         
30         ActionList layout = new ActionList(Activity.INFINITY);
31         layout.add(color);
32         layout.add(new ForceDirectedLayout("graph"));
33         layout.add(new RepaintAction());
34         
35         Display display = new Display(vis);
36         display.setSize(400, 500);
37         display.pan(250, 250);
38         display.addControlListener(new DragControl());
39         display.addControlListener(new PanControl());
40         display.addControlListener(new ZoomControl());
41         display.addControlListener(new WheelZoomControl());
42         display.addControlListener(new FocusControl(1));
43         display.addControlListener(new ZoomToFitControl());
44         
45         vis.putAction("color", color);
46         vis.putAction("layout", layout);
47         
48         
49         JFrame frame = new JFrame();
50         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
51         frame.pack();
52         frame.setSize(600, 700);
53         frame.add(display);
54         frame.setVisible(true);
55         
56         vis.run("color");
57         vis.run("layout");
58     }
59     
60 } 

 

  從代碼可以看出,對於創建節點、添加邊,Graph處理的游刃有余,只有你想不到的圖形,沒有創建不了的Graph。當然只是簡單創建了node和edge只是有了骨架,還需要血肉的填充,所以可以看到有很多的Action紛紛來助陣,最終的眾志成城之作如下:

 

 

  Demo3:誰說點點之間只能“直腸子”——EdgeRenderer的使用

 

  看不慣點與點之間的“直腸子”?可以,Prefuse了解你,知道你喜新厭舊,這不使用EdgeRenderer就可以實現曲線連接,具體代碼與Demo1相近,只是多了一下幾行代碼:

 

1 DefaultRendererFactory rf = new DefaultRendererFactory(label);
2 EdgeRenderer edgeRenderer = new EdgeRenderer(Constants.EDGE_TYPE_CURVE);
3 rf.add(new InGroupPredicate("graph.edges"), edgeRenderer);

 

  這里采用EdgeRenderer邊渲染器,將邊渲染為曲線,並統一應用到組“graph.edges”中的元素上,除了Constants.EDGE_TYPE_CURVE,還有Constants.EDGE_ARROW_FORWARD、Constants.EDGE_ARROW_NONE等。話不多說,看效果:

 

Demo4:Prefuse沒節操?不知道篩選?No!——Predicate的使用

Prefuse自帶過濾器,可以完成十分強大的過濾操作,視個別情況個別對待。拿Demo2中的圖形來說,處在中間的節點可以不收節點控制(無法拖拽,不能交互),人家兄弟姐妹多,就拿那些勢力若的邊緣小弟拖過來拽過去^_^。具體代碼如下:

 1 public class Demo4{
 2 
 3     public static void main(String[] argv) {
 4         Visualization vis = new Visualization();
 5         Graph g = new Graph();
 6         for(int i = 0; i<3; i++){
 7             Node n1 = g.addNode();
 8             Node n2 = g.addNode();
 9             Node n3 = g.addNode();
10             g.addEdge(n1, n2);
11             g.addEdge(n2, n3);
12             g.addEdge(n3, n1);
13         }
14         g.addEdge(0, 3);
15         g.addEdge(3, 6);
16         g.addEdge(6, 0);
17         vis.add("graph", g);
18 
19         ShapeRenderer renderer = new ShapeRenderer(10);
20         EdgeRenderer edgeRenderer = new EdgeRenderer(Constants.EDGE_TYPE_CURVE);
21         DefaultRendererFactory drf = new DefaultRendererFactory();
22         drf.add(new InGroupPredicate("graph.edges"), edgeRenderer);
23         vis.setRendererFactory(drf);
24         
25         ColorAction nodeFill = new ColorAction("graph.nodes", VisualItem.FILLCOLOR, ColorLib.rgb(10, 150, 220));
26         ColorAction edgesStroke = new ColorAction("graph.edges", VisualItem.STROKECOLOR, ColorLib.rgb(100, 80, 180));
27         ColorAction nodeHighlight = new ColorAction("graph.nodes", VisualItem.HIGHLIGHT, ColorLib.rgb(10, 150, 220));
28         
29         ShapeAction  shape = new ShapeAction("graph.nodes",Constants.SHAPE_CROSS); //設置節點形狀
30 
31         ActionList color = new ActionList();
32         color.add(nodeFill);
33         color.add(edgesStroke);
34         color.add(shape);
35         
36         ActionList layout = new ActionList(Activity.INFINITY);
37         layout.add(color);
38         layout.add(new ForceDirectedLayout("graph"));
39         layout.add(new RepaintAction());
40         
41         Point p = new Point(100,200);
42         p.move(300, 400);
43         
44         
45         Predicate pCount =(Predicate)ExpressionParser.parse("degree()>2");
46         
47         Display display = new Display(vis);
48         display.setSize(400, 500);
49         display.pan(250, 250);
50         display.animatePanAbs(230, 220, 2000);        
51         display.addControlListener(new DragControl());
52         display.addControlListener(new PanControl());
53         display.addControlListener(new ZoomControl());
54         display.addControlListener(new WheelZoomControl());
55         display.addControlListener(new FocusControl(1));
56         display.addControlListener(new ZoomToFitControl());
57         
58         vis.removeGroup("graph");
59         VisualGraph vg = vis.addGraph("graph", g);
60         Iterator nodes = vg.nodes();
61         display.addControlListener(new ControlAdapter() {
62             public void itemEntered(VisualItem item, MouseEvent e) {
63                 System.out.println("倫家已經是:" + item.getGroup()+"的人了");
64             }
65             public void itemExited(VisualItem item, MouseEvent e) {
66                 System.out.println("哦,那傑哥再找找-_-");
67             }
68         });//為組件添加監控並作相應的響應
69         
70         vis.setInteractive("graph.nodes", pCount, false);
71         
72         vis.putAction("color", color);
73         vis.putAction("layout", layout);
74         
75         
76         JFrame frame = new JFrame();
77         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
78         frame.pack();
79         frame.setSize(600, 700);
80         frame.add(display);
81         frame.setVisible(true);
82                 
83         vis.run("color");
84         vis.run("layout");
85     }
86     
87 } 

 

  這里Predicate pCount =(Predicate)ExpressionParser.parse("degree()>2")表示過濾出節點度數大於2的,該過濾條件在vis.setInteractive("graph.nodes", pCount, false)中執行,即在組“graph.nodes”元素中節點度數大於2的不能交互(即鼠標拖拽無效)。

 

  另外從代碼中可以看出當鼠標經過和離開VisualItem(點或邊)時會執行相應的操作,下圖展現了部分結果:

 

 

  Demo5:個性化定制,我有我個性——VisualItem的領悟

 

  要知道,在數據中心Visualizaiton里,每一個node或是edge都可以看成一個VisualItem,每個VisualItem都可以有屬於自己的造型、尺寸,這里我們還是用Demo2中的圖形繼續玩,直到玩壞為止。具體代碼如下:

 

 1 public class Demo5{
 2     public static Visualization vis = new Visualization();
 3     
 4     public static void main(String[] argv) {
 5         
 6         Graph g = new Graph();
 7         for(int i = 0; i<3; i++){
 8             Node n1 = g.addNode();
 9             Node n2 = g.addNode();
10             Node n3 = g.addNode();
11             g.addEdge(n1, n2);
12             g.addEdge(n2, n3);
13             g.addEdge(n3, n1);
14         }
15         g.addEdge(0, 3);
16         g.addEdge(3, 6);
17         g.addEdge(6, 0);
18         
19         vis.add("graph", g);
20         ShapeRenderer renderer = new ShapeRenderer(10);
21         vis.setRendererFactory(new DefaultRendererFactory(renderer));
22 
23         vis.removeGroup("graph");
24         VisualGraph vg = vis.addGraph("graph", g);
25         VisualItem nodeI = (VisualItem)vg.getEdge(7).getSourceNode();
26         nodeI.setShape(Constants.SHAPE_STAR);
27         nodeI.setSize(4);
28         nodeI.setFixed(true);
29         VisualItem edgeI = (VisualItem)vg.getEdge(5);
30         edgeI.setSize(8);
31         
32         ColorAction nodeFill = new ColorAction("graph.nodes", VisualItem.FILLCOLOR, ColorLib.rgb(10, 150, 220));
33         ColorAction edgesStroke = new ColorAction("graph.edges", VisualItem.STROKECOLOR, ColorLib.rgb(100, 80, 180));
34         ColorAction nodeHighlight = new ColorAction("graph.nodes", VisualItem.HIGHLIGHT, ColorLib.rgb(10, 150, 220));
35         
36         ActionList color = new ActionList();
37         color.add(nodeFill);
38         color.add(edgesStroke);
39         
40         ActionList layout = new ActionList(3000);
41         layout.add(color);
42         layout.add(new ForceDirectedLayout("graph"));
43         layout.add(new RepaintAction());
44         
45         Display display = new Display(vis);
46         display.setSize(400, 500);
47         display.pan(250, 250);
48         display.addControlListener(new DragControl());
49         display.addControlListener(new PanControl());
50         display.addControlListener(new ZoomControl());
51         display.addControlListener(new WheelZoomControl());
52         display.addControlListener(new FocusControl(1));
53         display.addControlListener(new ZoomToFitControl());
54         display.addControlListener(new ControlAdapter(){
55             public void itemEntered(VisualItem item, MouseEvent e) {
56                 
57                 System.out.println("倫家已經是:" + item.getGroup()+"的人了");
58                 vis.run("color");
59                 vis.run("layout");//重繪三秒
60             }
61         });
62         
63         vis.putAction("color", color);
64         vis.putAction("layout", layout);
65         
66         
67         JFrame frame = new JFrame();
68         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
69         frame.pack();
70         frame.setSize(600, 700);
71         frame.add(display);
72         frame.setVisible(true);
73         
74         vis.run("color");
75         vis.run("layout");
76     }
77     
78 } 

 

  可以看出代碼中nodeI.setShape(Constants.SHAPE_STAR);nodeI.setSize(4);nodeI.setFixed(true);是將節點的形狀設為星形,大小放大為4並固定此節點;edgeI.setSize(8);將邊的粗細設為8。這里還具有一個功能,就是代碼跑起來顯示圖形運行三秒,當鼠標經過某點或邊是,整個圖形在運行三秒,為展示這種效果,首次使用ps做gif,想想也是醉了。。。

 

 

  Prefuse就先玩到這吧,真材實料送上5個Demo,雖然搶不到紅包,搶點Demo補補腦也不錯哦,走到這里,似乎我已經拉近了與Prefuse的距離,下一步就是力求親密接觸,碰撞出可視化狂拽炫酷的展示效果。覺得有用,記得點贊哦。

本文鏈接:漫談可視化Prefuse(四)---被玩壞的Prefuse APIhttp://www.cnblogs.com/bigdataZJ/p/VisualizationSoloShow4.html

 

友情贊助

如果你覺得博主的文章對你那么一點小幫助,恰巧你又有想打賞博主的小沖動,那么事不宜遲,趕緊掃一掃,小額地贊助下,攢個奶粉錢,也是讓博主有動力繼續努力,寫出更好的文章^^。

    1. 支付寶                          2. 微信

                      


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM