`
kavy
  • 浏览: 890965 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

java程序如何调用Graphviz

 
阅读更多
。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语言 用来编写绘图脚本,然后对这个脚本进行解析,分析出其中的定点,边以及子图,然后根据属性进行绘制。具体的可以看一个例子,这个例子来自官方的文档。

 

[c-sharp] view plaincopy
 
  1. digraph G {  
  2.     main -> parse -> execute;  
  3.     main -> init;  
  4.     main -> cleanup;  
  5.     execute -> make_string;  
  6.     execute -> printf  
  7.     init -> make_string;  
  8.     main -> printf;  
  9.     execute -> compare;  
  10. }  

 

digraph指定该图是一个有向图(directed graph),->表示一条边,main,parse,execute等是顶点,运行出来的效果很好看,如下图:


 

需要注意的是,我在这个dot脚本中没有指定任何的关于图的位置的信息,布局器会自动的根据图形的类型进行布局,并最终展现出来。

再来看一个比较复杂,并且是程序员经常使用的功能,数据结构图:

 

[c-sharp] view plaincopy
 
  1. digraph g {  
  2.     node [shape = record,height=.1];  
  3.     node0[label = "<f0> |<f1> G|<f2> "];  
  4.     node1[label = "<f0> |<f1> E|<f2> "];  
  5.     node2[label = "<f0> |<f1> B|<f2> "];  
  6.     node3[label = "<f0> |<f1> F|<f2> "];  
  7.     node4[label = "<f0> |<f1> R|<f2> "];  
  8.     node5[label = "<f0> |<f1> H|<f2> "];  
  9.     node6[label = "<f0> |<f1> Y|<f2> "];  
  10.     node7[label = "<f0> |<f1> A|<f2> "];  
  11.     node8[label = "<f0> |<f1> C|<f2> "];  
  12.     "node0":f2 -> "node4":f1;  
  13.     "node0":f0 -> "node1":f1;  
  14.     "node1":f0 -> "node2":f1;  
  15.     "node1":f2 -> "node3":f1;  
  16.     "node2":f2 -> "node8":f1;  
  17.     "node2":f0 -> "node7":f1;  
  18.     "node4":f2 -> "node6":f1;  
  19.     "node4":f0 -> "node5":f1;  
  20. }  

 

运行后的效果如下图所示:

 

 

 

不知道其他的程序员怎样,反正我对命令行情有独钟,比较喜欢这一类的工具。最早接触的计算机系统正是一个没有图形系统的BSD,由此对命令行的,没 有界面的程序都特别感兴趣。

相关的想法

自从使用了graphviz以后,一直想着把这个好东西移植到java下来,大概的思想跟graphviz类似:

  • 解析dot脚本,生成图的对象,这个图中包括节点,边以及子图等对象,这些对象上都绑定着相应的属性
  • 将解析出来的图对象发送给layout engine进行处理,layout engine可以选择布局策略,比如流布局等
  • 从layout engine中得到布局后的图对象,并交给image engine处理,得到最终结果,负责展示或者保存等

dot 的语法定义比较简单,我已经用javacc构造了一个dot的分析器,现在可以从dot文件中构建出图对象出来,不过还需要进一步完善,可以看看这个 BNF定义:

 

 

[c-sharp] view plaincopy
 
  1. graph -> [strict] (digraph|graph) id '{' stmt-list '}'  
  2. stmt-list -> [stmt [';'] [stmt-list] ]  
  3. stmt -> attr-stmt | node-stmt | edge-stmt | subgraph | id '=' id  
  4. attr-stmt -> (graph | node | edge) attr-list  
  5. attr-list -> '[' [a-list] ']' [attr-list]  
  6. a-list -> id '=' id [','][a-list]  
  7. node-stmt -> node-id [attr-list]  
  8. node-id -> id [port]  
  9. port -> port-location [port-angle] | port-angle [port-location]  
  10. port-location -> ':' id | ':' '(' id ',' id ')'  
  11. port-angle ->'@' id  
  12. edge-stmt -> (node-id | subgraph) edgeRHS [attr-list]  
  13. edgeRHS -> edgeop (node-id | subgraph) [edgeRHS]  
  14. 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如下:

 

[c-sharp] view plaincopy
 
  1. public static void main(String[] args){  
  2.     Parser parser = new GCodeParser("file.g");  
  3.     GraphSet gs = parser.parse();  
  4.     GraphSet layouted =   
  5.         new GraphLayoutEngine(gs).layout();  
  6.     ImageEngine imgEngine =   
  7.         new GraphImageEngine(layouted);  
  8.     imgEngine.export(0);  
  9. }  

 

 

同graphviz一样,先调用分析器构造出图的集合GraphSet(包括多个图,每个图中包括Vertex,Edge,及SubGraph), 然后进行布局,最后将通过布局后的GraphSet绘制结果。目前完成了框架的设计部分,分析器部分基本完成,layout部分只实现了一个策略,即force-based 布局算法,不过layout engine被设计成可以插拔的模型,如果有了新的算法实现,可以很容易的整合起来。

 

dot.exe  -Tpng -o new.png -Kdot new.dot

分享到:
评论

相关推荐

    graphviz_print_graph:在Java中打印GraphViz图形

    例如,你可能想用GraphViz来展示树形结构、图算法的结果或者程序调用堆栈。 为了进一步定制图形的外观,你可以使用GraphViz的DOT语言来定义节点和边的属性,如颜色、形状、标签等。例如: ```java Node nodeA = ...

    soot生成java程序的控制流图例子

    总之,Soot提供了一种强大而灵活的方法来生成和分析Java程序的控制流图,结合Graphviz的可视化功能,可以帮助开发者更好地理解和优化代码。通过对代码的控制流图进行深入研究,可以识别出死代码、循环依赖、条件分支...

    graphviz下载

    在IT行业中,特别是在软件开发领域,Graphviz常被用来生成类图、调用图和依赖关系图,这些图能够直观地展示代码结构和程序之间的关系。与Doxygen结合使用时,它可以为源代码文档添加视觉元素,让开发者更容易理解和...

    graphviz免费.rar

    7. API与库集成:如果教程深入,可能会介绍如何在Python、Java、C++等编程语言中调用Graphviz的库进行程序化绘图。 "graphviz压缩包.rar"可能包含了一些示例图的源代码(DOT文件)和对应的输出图像,供学习者参考和...

    graphviz-2.38.zip

    例如,你可以用它来表示程序调用关系、数据依赖性或者组织结构。 dot命令还可以与其他工具,如“soot”,配合使用。Soot是一个Java优化框架,它可以处理Java类文件,并对其进行分析和转换。当与Graphviz结合时,...

    doxygen-1.6.1和graphviz-2.24安装程序

    **doxygen** 是一款强大的源代码文档生成工具,它能够自动从C++、C、Java、Python等众多编程语言的源代码中提取文档。在软件开发过程中,良好的文档是至关重要的,doxygen可以帮助开发者轻松地创建专业级别的API文档...

    Doxygen + Graphviz 很强大啊

    在编程中,Graphviz常被用来描绘软件架构、包依赖关系或程序调用图。通过与Doxygen结合,Graphviz能将源代码中的类和函数关系可视化,使开发者更容易理解和调试代码。 回到描述中提到的博文链接,虽然具体内容无法...

    graphviz.zip

    Graphviz支持多种编程语言的接口,如Python、Java、C++等,可以方便地在代码中调用Graphviz生成图表。这使得它能与其他数据分析或开发工具结合,实现自动化报告或可视化。 6. **图形样式和布局** Graphviz提供了...

    graphviz-2.24.0.tar.gz

    - **库文件**:供开发者在其他程序中调用Graphviz功能的动态或静态链接库。 - **示例**:包含各种示例图形和DOT脚本,展示Graphviz的功能和用法。 - **图形过滤器**:如`cvt`,用于转换图形格式。 - **开发工具**:...

    graphviz-2.30.1.zip

    在开发过程中,Graphviz可以与其他编程语言如Python、Java、C++等集成,通过API调用生成图形。例如,Python的`pygraphviz`库就提供了与Graphviz交互的接口,方便在Python程序中创建和展示图。 总的来说,Graphviz-...

    性能优化工具 valgrind+graphviz+gprof2dot

    3. **gprof2dot**:gprof2dot是将gprof的输出转换为DOT语言(Graphviz的一种输入格式)的工具,使得gprof的调用图可以利用Graphviz进行可视化。gprof是GCC编译器自带的性能分析工具,它可以分析程序的CPU时间分布,...

    graphviz-2.16.1

    这样,doxygen在生成文档时会调用Graphviz将这些代码转化为图形,从而在文档中展示出代码的结构和相互关系。 总的来说,Graphviz-2.16.1是IT专业人士进行代码可视化、设计流程可视化或任何需要图形表示的复杂系统时...

    Soot的Java程序控制流分析及图形化输出.pdf

    对于Java程序而言,Soot框架的出现为开发者提供了一种强大的工具,它不仅能够分析和优化Java字节码,还可以通过图形化的方式直观展现程序的控制流。本文将深入探讨Soot框架在Java程序控制流分析及图形化输出方面的...

    graphviz.msi windows安装文件

    5. **库支持**:Graphviz提供了C、C++、Python、Java等编程语言的API,使得开发者能够将图形绘制功能集成到自己的应用程序中。 6. **社区与资源**:Graphviz拥有活跃的社区,用户可以在这里找到示例、教程和插件,...

    doxygen和graphviz文档生成工具.rar

    Graphviz则是一个图形绘制工具,能够自动生成各种图表,包括程序的调用图、继承图和协作图等。在软件文档中,这些图形对于理解和展示代码间的相互关系至关重要。Graphviz使用DOT语言来描述图形结构,通过简单的文本...

    graphviz 图像下载包

    5. **集成开发环境支持**:Graphviz 可以与许多编程语言(如 Python、Java、C++ 等)集成,通过 API 调用进行图形的生成和操作,这在机器学习项目中非常有用,可以方便地动态展示模型结构。 6. **社区与资源**:...

    Doxygen+Graphviz

    在源码分析中,Graphviz可以用来展示类之间的继承关系、函数调用链等抽象的程序结构。通过使用DOT语言,开发者可以描述对象和它们之间的关系,然后Graphviz会根据这些描述生成美观且直观的图形。 将Doxygen与...

    graphviz 2.24 doxygen用来生成关系图的插件

    Doxygen可以调用Graphviz来生成图形,这样在文档中就可以看到清晰的类结构和调用关系。例如,类图可以显示类之间的继承关系,每个类的成员函数和属性,而调用图则能展示函数间的调用顺序,帮助理解代码执行流程。 ...

    graphviz 2.38

    6. **扩展与集成**: Graphviz可与其他编程语言如Python、Java、C++等进行集成,允许开发人员在应用程序中调用Graphviz的功能。此外,还有一系列的插件和库,如PyGraphviz、JGraphViz等,便于编程操作。 7. **社区...

Global site tag (gtag.js) - Google Analytics