。java可以直接调用这个类实现画图功能,但是使用这个类的前提是你的电脑已经装了GraphViz软件,你可以在http://www.graphviz.org/Gallery.php下载windows版本,装完后,找到dot.exe所在的路径,我电脑上的是D:\Program Files\Graphviz2.30\bin\dot.exe, 将GraphViz.java中的这一路径改成你电脑上的路径,基本上就可以用了。 package Graphoutput; // GraphViz.java - a simple API to call dot from Java programs /*$Id$*/ /* ****************************************************************************** * * * (c) Copyright 2003 Laszlo Szathmary * * * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU Lesser General Public License as published by * * the Free Software Foundation; either version 2.1 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * * License for more details. * * * * You should have received a copy of the GNU Lesser General Public License * * along with this program; if not, write to the Free Software Foundation, * * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * * ****************************************************************************** */ import java.io.BufferedReader; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.InputStreamReader; /** * <dl> * <dt>Purpose: GraphViz Java API * <dd> * * <dt>Description: * <dd> With this Java class you can simply call dot * from your Java programs * <dt>Example usage: * <dd> * <pre> * GraphViz gv = new GraphViz(); * gv.addln(gv.start_graph()); * gv.addln("A -> B;"); * gv.addln("A -> C;"); * gv.addln(gv.end_graph()); * System.out.println(gv.getDotSource()); * * String type = "gif"; * File out = new File("out." + type); // out.gif in this example * gv.writeGraphToFile( gv.getGraph( gv.getDotSource(), type ), out ); * </pre> * </dd> * * </dl> * * @version v0.4, 2011/02/05 (February) -- Patch of Keheliya Gallaba is added. Now you * can specify the type of the output file: gif, dot, fig, pdf, ps, svg, png, etc. * @version v0.3, 2010/11/29 (November) -- Windows support + ability * to read the graph from a text file * @version v0.2, 2010/07/22 (July) -- bug fix * @version v0.1, 2003/12/04 (December) -- first release * @author Laszlo Szathmary (<a href="jabba.laci@gmail.com">jabba.laci@gmail.com</a>) */ public class GraphViz { /** * The dir. where temporary files will be created. */ //private static String TEMP_DIR = "/tmp"; // Linux private static String TEMP_DIR = "c:/temp"; // Windows /** * Where is your dot program located? It will be called externally. */ // private static String DOT = "/usr/bin/dot"; // Linux private static String DOT = "D:\\Program Files\\Graphviz2.30\\bin\\dot.exe"; // Windows /** * The source of the graph written in dot language. */ private StringBuilder graph = new StringBuilder(); /** * Constructor: creates a new GraphViz object that will contain * a graph. */ public GraphViz() { } /** * Returns the graph's source description in dot language. * @return Source of the graph in dot language. */ public String getDotSource() { return graph.toString(); } /** * Adds a string to the graph's source (without newline). */ public void add(String line) { graph.append(line); } /** * Adds a string to the graph's source (with newline). */ public void addln(String line) { graph.append(line + "\n"); } /** * Adds a newline to the graph's source. */ public void addln() { graph.append('\n'); } /** * Returns the graph as an image in binary format. * @param dot_source Source of the graph to be drawn. * @param type Type of the output image to be produced, e.g.: gif, dot, fig, pdf, ps, svg, png. * @return A byte array containing the image of the graph. */ public byte[] getGraph(String dot_source, String type) { File dot; byte[] img_stream = null; try { dot = writeDotSourceToFile(dot_source); if (dot != null) { img_stream = get_img_stream(dot, type); if (dot.delete() == false) System.err.println("Warning: " + dot.getAbsolutePath() + " could not be deleted!"); return img_stream; } return null; } catch (java.io.IOException ioe) { return null; } } /** * Writes the graph's image in a file. * @param img A byte array containing the image of the graph. * @param file Name of the file to where we want to write. * @return Success: 1, Failure: -1 */ public int writeGraphToFile(byte[] img, String file) { File to = new File(file); return writeGraphToFile(img, to); } /** * Writes the graph's image in a file. * @param img A byte array containing the image of the graph. * @param to A File object to where we want to write. * @return Success: 1, Failure: -1 */ public int writeGraphToFile(byte[] img, File to) { try { FileOutputStream fos = new FileOutputStream(to); fos.write(img); fos.close(); } catch (java.io.IOException ioe) { ioe.printStackTrace();return -1; } return 1; } /** * It will call the external dot program, and return the image in * binary format. * @param dot Source of the graph (in dot language). * @param type Type of the output image to be produced, e.g.: gif, dot, fig, pdf, ps, svg, png. * @return The image of the graph in .gif format. */ private byte[] get_img_stream(File dot, String type) { File img; byte[] img_stream = null; try { img = File.createTempFile("graph_", "."+type, new File(GraphViz.TEMP_DIR)); Runtime rt = Runtime.getRuntime(); // patch by Mike Chenault String[] args = {DOT, "-T"+type, dot.getAbsolutePath(), "-o", img.getAbsolutePath()}; Process p = rt.exec(args); p.waitFor(); FileInputStream in = new FileInputStream(img.getAbsolutePath()); img_stream = new byte[in.available()]; in.read(img_stream); // Close it if we need to if( in != null ) in.close(); if (img.delete() == false) System.err.println("Warning: " + img.getAbsolutePath() + " could not be deleted!"); } catch (java.io.IOException ioe) { System.err.println("Error: in I/O processing of tempfile in dir " + GraphViz.TEMP_DIR+"\n"); System.err.println(" or in calling external command"); ioe.printStackTrace(); } catch (java.lang.InterruptedException ie) { System.err.println("Error: the execution of the external program was interrupted"); ie.printStackTrace(); } return img_stream; } /** * Writes the source of the graph in a file, and returns the written file * as a File object. * @param str Source of the graph (in dot language). * @return The file (as a File object) that contains the source of the graph. */ public File writeDotSourceToFile(String str) throws java.io.IOException { File temp; try { temp = File.createTempFile("graph_", ".dot.tmp", new File(GraphViz.TEMP_DIR)); FileWriter fout = new FileWriter(temp); fout.write(str); fout.close(); } catch (Exception e) { System.err.println("Error: I/O error while writing the dot source to temp file!"); return null; } return temp; } /** * Returns a string that is used to start a graph. * @return A string to open a graph. */ public String start_graph() { return "digraph G {" ; } /** * Returns a string that is used to end a graph. * @return A string to close a graph. */ public String end_graph() { return "}"; } /** * Read a DOT graph from a text file. * * @param input Input text file containing the DOT graph * source. */ public void readSource(String input) { StringBuilder sb = new StringBuilder(); try { FileInputStream fis = new FileInputStream(input); DataInputStream dis = new DataInputStream(fis); BufferedReader br = new BufferedReader(new InputStreamReader(dis)); String line; while ((line = br.readLine()) != null) { sb.append(line); } dis.close(); } catch (Exception e) { System.err.println("Error: " + e.getMessage()); } this.graph = sb; } } // end of class GraphViz 通过下面这个类调用graphViz.java import java.io.File; public class Proba { public static void main(String[] args) { Proba p = new Proba(); p.start(); // p.start2(); } /** * Construct a DOT graph in memory, convert it * to image and store the image in the file system. */ private void start() { GraphViz gv = new GraphViz(); gv.addln(gv.start_graph()); gv.addln("A -> B;"); gv.addln("A -> C;"); gv.addln(gv.end_graph()); System.out.println(gv.getDotSource()); String type = "gif"; // String type = "dot"; // String type = "fig"; // open with xfig // String type = "pdf"; // String type = "ps"; // String type = "svg"; // open with inkscape // String type = "png"; // String type = "plain"; File out = new File("/tmp/out." + type); // Linux // File out = new File("c:/eclipse.ws/graphviz-java-api/out." + type); // Windows gv.writeGraphToFile( gv.getGraph( gv.getDotSource(), type ), out ); } /** * Read the DOT source from a file, * convert to image and store the image in the file system. */ private void start2() { // String dir = "/home/jabba/eclipse2/laszlo.sajat/graphviz-java-api"; // Linux // String input = dir + "/sample/simple.dot"; String input = "c:/eclipse.ws/graphviz-java-api/sample/simple.dot"; // Windows GraphViz gv = new GraphViz(); gv.readSource(input); System.out.println(gv.getDotSource()); String type = "gif"; // String type = "dot"; // String type = "fig"; // open with xfig // String type = "pdf"; // String type = "ps"; // String type = "svg"; // open with inkscape // String type = "png"; // String type = "plain"; File out = new File("/tmp/simple." + type); // Linux // File out = new File("c:/eclipse.ws/graphviz-java-api/tmp/simple." + type); // Windows gv.writeGraphToFile( gv.getGraph( gv.getDotSource(), type ), out ); } }
Graphviz介绍
graphviz是贝尔实验室几个计算机牛人设计的一个开源 的图表(计算机科学中数据结构中的图)可视化项目,主要用C语言实现,主要实现了一些图布局算法。通过这些算法,可以将图中的节点在画布上比较均匀的分 布,缩短节点之间的边长,并且尽量的减少边的交叉。
graphviz提供命令式的绘图方式,它提供一个dot语言 用来编写绘图脚本,然后对这个脚本进行解析,分析出其中的定点,边以及子图,然后根据属性进行绘制。具体的可以看一个例子,这个例子来自官方的文档。
- digraph G {
- main -> parse -> execute;
- main -> init;
- main -> cleanup;
- execute -> make_string;
- execute -> printf
- init -> make_string;
- main -> printf;
- execute -> compare;
- }
digraph指定该图是一个有向图(directed graph),->表示一条边,main,parse,execute等是顶点,运行出来的效果很好看,如下图:
需要注意的是,我在这个dot脚本中没有指定任何的关于图的位置的信息,布局器会自动的根据图形的类型进行布局,并最终展现出来。
再来看一个比较复杂,并且是程序员经常使用的功能,数据结构图:
- digraph g {
- node [shape = record,height=.1];
- node0[label = "<f0> |<f1> G|<f2> "];
- node1[label = "<f0> |<f1> E|<f2> "];
- node2[label = "<f0> |<f1> B|<f2> "];
- node3[label = "<f0> |<f1> F|<f2> "];
- node4[label = "<f0> |<f1> R|<f2> "];
- node5[label = "<f0> |<f1> H|<f2> "];
- node6[label = "<f0> |<f1> Y|<f2> "];
- node7[label = "<f0> |<f1> A|<f2> "];
- node8[label = "<f0> |<f1> C|<f2> "];
- "node0":f2 -> "node4":f1;
- "node0":f0 -> "node1":f1;
- "node1":f0 -> "node2":f1;
- "node1":f2 -> "node3":f1;
- "node2":f2 -> "node8":f1;
- "node2":f0 -> "node7":f1;
- "node4":f2 -> "node6":f1;
- "node4":f0 -> "node5":f1;
- }
运行后的效果如下图所示:
不知道其他的程序员怎样,反正我对命令行情有独钟,比较喜欢这一类的工具。最早接触的计算机系统正是一个没有图形系统的BSD,由此对命令行的,没 有界面的程序都特别感兴趣。
相关的想法
自从使用了graphviz以后,一直想着把这个好东西移植到java下来,大概的思想跟graphviz类似:
- 解析dot脚本,生成图的对象,这个图中包括节点,边以及子图等对象,这些对象上都绑定着相应的属性
- 将解析出来的图对象发送给layout engine进行处理,layout engine可以选择布局策略,比如流布局等
- 从layout engine中得到布局后的图对象,并交给image engine处理,得到最终结果,负责展示或者保存等
dot 的语法定义比较简单,我已经用javacc构造了一个dot的分析器,现在可以从dot文件中构建出图对象出来,不过还需要进一步完善,可以看看这个 BNF定义:
- graph -> [strict] (digraph|graph) id '{' stmt-list '}'
- stmt-list -> [stmt [';'] [stmt-list] ]
- stmt -> attr-stmt | node-stmt | edge-stmt | subgraph | id '=' id
- attr-stmt -> (graph | node | edge) attr-list
- attr-list -> '[' [a-list] ']' [attr-list]
- a-list -> id '=' id [','][a-list]
- node-stmt -> node-id [attr-list]
- node-id -> id [port]
- port -> port-location [port-angle] | port-angle [port-location]
- port-location -> ':' id | ':' '(' id ',' id ')'
- port-angle ->'@' id
- edge-stmt -> (node-id | subgraph) edgeRHS [attr-list]
- edgeRHS -> edgeop (node-id | subgraph) [edgeRHS]
- subgraph -> [subgraph id] '{' stmt-list '}' | subgraph id
(最近老是感觉时间不够用,有很多有意思的项目要做,比如要完善前几天说的那个bbms(Bus Based Message Service), 再比如修改用Swing和Smack做一个jabber的客户端jTalk,都是很有搞头的,唉,扯远了。)
当然graphviz的功能不至于此,它提供一个lib,可以用来将绘图引擎嵌入在自己的应用中。这是一个很有意义的事,我们可以不必掌握布局部分 的复杂算法,把精力放在业务逻辑部分,将最后的图对象交给这个引擎来处理即可。当然,如果你正好和我一样,想了解其神奇的布局算法,不妨翻翻它的源码,欢 迎交流之至。
我在周末分析了下graphviz的内部结构,并建立了一个java的项目jraph ,用来做简单的移植,主要是学习之用,其实,Java的图库还是相当丰富的,比如JGraph ,JGraphT,Prefuse,TouchGraph等等,用来做项目当然是很便捷的,但是我还是比较喜欢看着一个算法被自己实现的过程,特别是这种 比较神奇的算法,哈哈。
预期中的API如下:
- public static void main(String[] args){
- Parser parser = new GCodeParser("file.g");
- GraphSet gs = parser.parse();
- GraphSet layouted =
- new GraphLayoutEngine(gs).layout();
- ImageEngine imgEngine =
- new GraphImageEngine(layouted);
- imgEngine.export(0);
- }
同graphviz一样,先调用分析器构造出图的集合GraphSet(包括多个图,每个图中包括Vertex,Edge,及SubGraph), 然后进行布局,最后将通过布局后的GraphSet绘制结果。目前完成了框架的设计部分,分析器部分基本完成,layout部分只实现了一个策略,即force-based 布局算法,不过layout engine被设计成可以插拔的模型,如果有了新的算法实现,可以很容易的整合起来。
dot.exe -Tpng -o new.png -Kdot new.dot
相关推荐
例如,你可能想用GraphViz来展示树形结构、图算法的结果或者程序调用堆栈。 为了进一步定制图形的外观,你可以使用GraphViz的DOT语言来定义节点和边的属性,如颜色、形状、标签等。例如: ```java Node nodeA = ...
总之,Soot提供了一种强大而灵活的方法来生成和分析Java程序的控制流图,结合Graphviz的可视化功能,可以帮助开发者更好地理解和优化代码。通过对代码的控制流图进行深入研究,可以识别出死代码、循环依赖、条件分支...
在IT行业中,特别是在软件开发领域,Graphviz常被用来生成类图、调用图和依赖关系图,这些图能够直观地展示代码结构和程序之间的关系。与Doxygen结合使用时,它可以为源代码文档添加视觉元素,让开发者更容易理解和...
7. API与库集成:如果教程深入,可能会介绍如何在Python、Java、C++等编程语言中调用Graphviz的库进行程序化绘图。 "graphviz压缩包.rar"可能包含了一些示例图的源代码(DOT文件)和对应的输出图像,供学习者参考和...
例如,你可以用它来表示程序调用关系、数据依赖性或者组织结构。 dot命令还可以与其他工具,如“soot”,配合使用。Soot是一个Java优化框架,它可以处理Java类文件,并对其进行分析和转换。当与Graphviz结合时,...
**doxygen** 是一款强大的源代码文档生成工具,它能够自动从C++、C、Java、Python等众多编程语言的源代码中提取文档。在软件开发过程中,良好的文档是至关重要的,doxygen可以帮助开发者轻松地创建专业级别的API文档...
在编程中,Graphviz常被用来描绘软件架构、包依赖关系或程序调用图。通过与Doxygen结合,Graphviz能将源代码中的类和函数关系可视化,使开发者更容易理解和调试代码。 回到描述中提到的博文链接,虽然具体内容无法...
Graphviz支持多种编程语言的接口,如Python、Java、C++等,可以方便地在代码中调用Graphviz生成图表。这使得它能与其他数据分析或开发工具结合,实现自动化报告或可视化。 6. **图形样式和布局** Graphviz提供了...
- **库文件**:供开发者在其他程序中调用Graphviz功能的动态或静态链接库。 - **示例**:包含各种示例图形和DOT脚本,展示Graphviz的功能和用法。 - **图形过滤器**:如`cvt`,用于转换图形格式。 - **开发工具**:...
在开发过程中,Graphviz可以与其他编程语言如Python、Java、C++等集成,通过API调用生成图形。例如,Python的`pygraphviz`库就提供了与Graphviz交互的接口,方便在Python程序中创建和展示图。 总的来说,Graphviz-...
3. **gprof2dot**:gprof2dot是将gprof的输出转换为DOT语言(Graphviz的一种输入格式)的工具,使得gprof的调用图可以利用Graphviz进行可视化。gprof是GCC编译器自带的性能分析工具,它可以分析程序的CPU时间分布,...
这样,doxygen在生成文档时会调用Graphviz将这些代码转化为图形,从而在文档中展示出代码的结构和相互关系。 总的来说,Graphviz-2.16.1是IT专业人士进行代码可视化、设计流程可视化或任何需要图形表示的复杂系统时...
5. **库支持**:Graphviz提供了C、C++、Python、Java等编程语言的API,使得开发者能够将图形绘制功能集成到自己的应用程序中。 6. **社区与资源**:Graphviz拥有活跃的社区,用户可以在这里找到示例、教程和插件,...
Graphviz则是一个图形绘制工具,能够自动生成各种图表,包括程序的调用图、继承图和协作图等。在软件文档中,这些图形对于理解和展示代码间的相互关系至关重要。Graphviz使用DOT语言来描述图形结构,通过简单的文本...
5. **集成开发环境支持**:Graphviz 可以与许多编程语言(如 Python、Java、C++ 等)集成,通过 API 调用进行图形的生成和操作,这在机器学习项目中非常有用,可以方便地动态展示模型结构。 6. **社区与资源**:...
在源码分析中,Graphviz可以用来展示类之间的继承关系、函数调用链等抽象的程序结构。通过使用DOT语言,开发者可以描述对象和它们之间的关系,然后Graphviz会根据这些描述生成美观且直观的图形。 将Doxygen与...
Doxygen可以调用Graphviz来生成图形,这样在文档中就可以看到清晰的类结构和调用关系。例如,类图可以显示类之间的继承关系,每个类的成员函数和属性,而调用图则能展示函数间的调用顺序,帮助理解代码执行流程。 ...
6. **扩展与集成**: Graphviz可与其他编程语言如Python、Java、C++等进行集成,允许开发人员在应用程序中调用Graphviz的功能。此外,还有一系列的插件和库,如PyGraphviz、JGraphViz等,便于编程操作。 7. **社区...
7. **库文件**:`lib`目录下的库文件是Graphviz运行的基础,它们包含了各种算法的实现和系统调用,为其他软件调用Graphviz功能提供支持。 8. **Pango集成**:Pango是用于文本布局和渲染的库,`pango`目录表明...