All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.integratedmodelling.utils.graph.GraphViz Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2011 The ARIES Consortium (http://www.ariesonline.org) and
 * www.integratedmodelling.org. 

   This file is part of Thinklab.

   Thinklab is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published
   by the Free Software Foundation, either version 3 of the License,
   or (at your option) any later version.

   Thinklab 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
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with Thinklab.  If not, see .
 */
package org.integratedmodelling.utils.graph;

//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.                              *
 *                                                                            *
 ******************************************************************************
 * 
 * Modified by Ferdinando Villa, Ecoinformatics Collaboratory, UVM
 * @date June 18, 2007
 */

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.IOException;
import java.io.InputStreamReader;
import java.util.Hashtable;
import java.util.Set;

import org.apache.commons.io.FileUtils;
import org.integratedmodelling.common.configuration.KLAB;
import org.integratedmodelling.common.utils.DisplayImage;
import org.integratedmodelling.exceptions.KlabException;
import org.integratedmodelling.exceptions.KlabIOException;
import org.jgrapht.DirectedGraph;

/**
 * 
*
Purpose: GraphViz Java API *
* *
Description: *
With this Java class you can simply call dot * from your Java programs *
Example usage: *
*
 *    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());
 *
 *    File out = new File("out.gif");
 *    gv.writeGraphToFile(gv.getGraph(gv.getDotSource()), out);
 * 
*
* *
* * @version v0.1, 2003/12/04 (Decembre) * @author Laszlo Szathmary ([email protected]) * * Modified by Ferdinando Villa, Ecoinformatics Collaboratory, UVM * @date June 18, 2007 */ public class GraphViz { private String makeImageMap = null; private String imageMap = ""; private String outputFormat = "png"; // these will be filled in only if layout() is called int width; int height; public static interface NodePropertiesProvider { /* * node shapes */ public final static String BOX = "box"; public final static String ELLIPSE = "ellipse"; public final static String HEXAGON = "hexagon"; public final static String OCTAGON = "octagon"; public final static String RECTANGLE = "rectangle"; public final static String COMPONENT = "component"; public final static String PARALLELOGRAM = "parallelogram"; public final static String BOX3D = "box3d"; public final static String FOLDER = "folder"; public final static String TAB = "tab"; public final static String DIAMOND = "diamond"; public final static String CDS = "cds"; public String getNodeId(N o); public String getNodeShape(N o); public int getNodeWidth(N o); public int getNodeHeight(N o); public String getEdgeColor(E e); public String getEdgeLabel(E e); } public class NodeLayout { int x; int y; int w; int h; String node; } Hashtable nodes = new Hashtable(); /* * Call this with a URL pattern if you want an imagemap to be generated for the graph. * @param The URL pattern that you want to attach to each node. Use %s in the pattern * where you want the node name to go. If the node name has spaces in them, they will be replaced by * underscores in the resulting URL. */ public void makeImageMap(String urlPattern) { makeImageMap = urlPattern; } /* * If makeImageMap(true) has been called and getGraph() executed, returns the * image map ready for inclusion in HTML. Otherwise returns an empty string. * @return */ public String getImageMap() { return imageMap; } /** * Set the output format to the passed string. It must be understood in the -T option * of graphviz executables, and it also becomes the filename extension. Use with caution, * no checking is done. * * @param outputFormat */ public void setOutputFormat(String outputFormat) { this.outputFormat = outputFormat; } static private String getDefaultDotPath(String exe) { String ret = "/usr/bin/" + exe; switch (KLAB.CONFIG.getOS()) { case WIN: ret = exe + ".exe"; break; case MACOS: /* TODO check where it goes */ ret = "/usr/bin/" + exe; break; case UNIX: /* TODO check where common rpm distributions put it */ ret = "/usr/bin/" + exe; break; } return ret; } private String DOT = null; /** * The source of the graph written in dot language. */ private StringBuffer graph = new StringBuffer(); /** * Constructor: creates a new GraphViz object that will contain * a graph. */ public GraphViz() { this("dot"); } /** * COnstructor that allows to specify the program you want to use. * @param graphvizProgram */ public GraphViz(String graphvizProgram) { DOT = KLAB.CONFIG.getProperties() .getProperty(graphvizProgram + ".path", getDefaultDotPath(graphvizProgram)); // if (! (new File(DOT).exists())) // throw new ThinklabResourceNotFoundException(DOT); } /** * Returns the graph's source description in dot language. * @return Source of the graph in dot language. */ public String getDotSource() { return graph.toString(); } /** * Add a node to the graph. * @param node * @param options */ public void addNode(String node, String options) { String s = "\tnode "; String a = options == null ? "" : options; if (makeImageMap != null) { // String nnode = node.replace(' ', '_'); // PrintfFormat fmt = new PrintfFormat(makeImageMap); // a += // (a.length() > 0 ? "," : "") + // "URL=\"" + // fmt.tostr(nnode) + // "\""; } /* add attributes if any */ if (a.length() > 0) { s += " [" + a + "] "; } s += "\"" + node + "\";"; addln(s); } /** * Add a directed edge between passed nodes. * @param vertexName * @param vertexName2 */ public void addDirectedEdge(String vertexName, String vertexName2, String options) { addln("\t\"" + vertexName + "\" -> \"" + vertexName2 + "\"" + (options == null ? "" : ("[" + options + "]"))); } public void loadGraph(DirectedGraph graph, NodePropertiesProvider npp) { loadGraph(graph, npp, false); } /** * Load a knowledge graph into graphviz representation. Do what you want after that. * Use reverse if the relationship shows the inverse of the intended semantics. * * @param graph */ public void loadGraph(DirectedGraph graph, NodePropertiesProvider npp, boolean reverse) { addln(start_graph("fontsize=8", "fontname=\"sanserif\"", "overlap=\"scale\"")); for (Object s : graph.vertexSet()) { addNode(npp.getNodeId(s), "shape=" + npp.getNodeShape(s) + ", fontname=sanserif, fontsize=8, margin=\"0.055\""); } for (Object e : graph.edgeSet()) { Object s = graph.getEdgeSource(e); Object t = graph.getEdgeTarget(e); addDirectedEdge((reverse ? npp.getNodeId(t) : npp.getNodeId(s)), (reverse ? npp.getNodeId(s) : npp.getNodeId(t)), ("label=\"" + npp.getEdgeLabel(e) + "\", color=\"" + npp.getEdgeColor(e) + "\", fontname=sanserif, fontsize=8")); } addln(end_graph()); } public void show() throws KlabException { try { File o = File.createTempFile("gdi", "gif"); writeGraphToFile(createImage(writeDotSourceToFile()), o); DisplayImage display = new DisplayImage(o.toURI().toURL()); display.setVisible(true); } catch (IOException e) { throw new KlabIOException(e); } } /** * 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. * @return A byte array containing the image of the graph. * @throws KlabException */ public byte[] getGraph() throws KlabException { byte[] img_stream = null; File dot = writeDotSourceToFile(); if (dot != null) img_stream = createImage(dot); return img_stream; } /** * 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) { return -1; } return 1; } /** * Use graphviz to generate a layout for the nodes and return a Layout object * that describes it. After that is done, the size of the diagram and coordinates * of all nodes can be retrieved using getWidth(), getHeight() and getNode[X/Y](). * * Coordinates are top to bottom, left to right if the passed parameter is true, * bottom to top otherwise. */ public void layout(NodePropertiesProvider npp, boolean top2bottom) throws KlabException { try { File img = File.createTempFile("graph_", ".txt"); File dot = writeDotSourceToFile(); Runtime rt = Runtime.getRuntime(); String cmd = DOT; cmd += (top2bottom ? " -Tplain -y -o" : " -Tplain -o") + img.getAbsolutePath(); cmd += " " + dot.getAbsolutePath(); Process p = rt.exec(cmd); p.waitFor(); /* parse layout file and set positions */ parseLayout(img); if (img.delete() == false || dot.delete() == false) System.err.println("Warning: " + img.getAbsolutePath() + " could not be deleted!"); } catch (Exception ioe) { throw new KlabIOException(ioe); } } private void parseLayout(File f) throws IOException { FileInputStream fstream = new FileInputStream(f); DataInputStream in = new DataInputStream(fstream); BufferedReader br = new BufferedReader(new InputStreamReader(in)); String line; while ((line = br.readLine()) != null) { String[] tokens = line.split("\\s+"); if (tokens.length < 2) continue; if (tokens[0].equals("graph")) { width = (int) (Float.parseFloat(tokens[2]) * 72); height = (int) (Float.parseFloat(tokens[3]) * 72); } else if (tokens[0].equals("node")) { NodeLayout nl = new NodeLayout(); nl.node = tokens[1]; nl.x = (int) (Float.parseFloat(tokens[2]) * 72); nl.y = (int) (Float.parseFloat(tokens[3]) * 72); nl.w = (int) (Float.parseFloat(tokens[4]) * 72); nl.h = (int) (Float.parseFloat(tokens[5]) * 72); nodes.put(nl.node, nl); } else if (tokens[0].equals("edge")) { /* ignore for now */ } } in.close(); } public int getWidth() { return width; } public int getHeight() { return height; } public int getNodeWidth(String node) { return nodes.get(node).w; } public int getNodeHeight(String node) { return nodes.get(node).h; } public int getNodeX(String node) { return nodes.get(node).x; } public int getNodeY(String node) { return nodes.get(node).y; } public Set getNodeNames() { return nodes.keySet(); } /** * It will call the external dot program, and return the image in * binary format. * @param dot Source of the graph (in dot language). * @return The image of the graph in .gif format. * @throws KlabException */ public byte[] createImage(File dot) throws KlabException { File img = null; File imap = null; byte[] img_stream = null; try { img = File.createTempFile("graph_", "." + outputFormat); imap = File.createTempFile("imap_", ".txt"); String temp = img.getAbsolutePath(); Runtime rt = Runtime.getRuntime(); String cmd = DOT; if (makeImageMap != null) { cmd += " -Tcmap -o" + imap.getAbsolutePath(); } cmd += " -T" + outputFormat + " -o" + img.getAbsolutePath(); cmd += " " + dot.getAbsolutePath(); Process p = rt.exec(cmd); 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 (makeImageMap != null) { FileUtils.readFileToString(imap); } if (img.delete() == false) System.err.println("Warning: " + img.getAbsolutePath() + " could not be deleted!"); } catch (Exception ioe) { throw new KlabIOException(ioe); } 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. */ private File writeDotSourceToFile() throws KlabIOException { File temp; try { temp = File.createTempFile("graph_", ".dot.tmp"); FileWriter fout = new FileWriter(temp); fout.write(getDotSource()); fout.close(); } catch (Exception e) { throw new KlabIOException(e); } return temp; } /** * Returns a string that is used to start a graph. * @return A string to open a graph. */ public String start_graph(String... options) { String ret = "digraph G {"; if (options != null) { for (String o : options) { ret += "\n\t" + o; } } return ret; } /** * Returns a string that is used to end a graph. * @return A string to close a graph. */ public String end_graph() { return "}"; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy