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

weka.gui.graphvisualizer.DotParser Maven / Gradle / Ivy

Go to download

The Waikato Environment for Knowledge Analysis (WEKA), a machine learning workbench. This version represents the developer version, the "bleeding edge" of development, you could say. New functionality gets added to this version.

There is a newer version: 3.9.6
Show newest version
/*
 *   This program 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.
 *
 *   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 General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see .
 */

/*
 *    DotParser.java
 *    Copyright (C) 2003-2012 University of Waikato, Hamilton, New Zealand
 *
 */
package weka.gui.graphvisualizer;

import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.StreamTokenizer;
import java.util.ArrayList;

/**
 * This class parses input in DOT format, and builds the datastructures that are
 * passed to it. It is NOT 100% compatible with the DOT format. The GraphNode
 * and GraphEdge classes do not have any provision for dealing with different
 * colours or shapes of nodes, there can however, be a different label and ID
 * for a node. It also does not do anything for labels for edges. However, this
 * class won't crash or throw an exception if it encounters any of the above
 * attributes of an edge or a node. This class however, won't be able to deal
 * with things like subgraphs and grouping of nodes.
 * 
 * @author Ashraf M. Kibriya ([email protected])
 * @version $Revision: 10222 $ - 23 Apr 2003 - Initial version (Ashraf M.
 *          Kibriya)
 */
public class DotParser implements GraphConstants {

  /** These holds the nodes and edges of the graph */
  protected ArrayList m_nodes;
  protected ArrayList m_edges;

  /** This is the input containing DOT stream to be parsed */
  protected Reader m_input;
  /** This holds the name of the graph if there is any otherwise it is null */
  protected String m_graphName;

  /**
   * 
   * Dot parser Constructor
   * 
   * @param input - The input, if passing in a string then encapsulate that in
   *          String reader object
   * @param nodes - Vector to put in GraphNode objects, corresponding to the
   *          nodes parsed in from the input
   * @param edges - Vector to put in GraphEdge objects, corresponding to the
   *          edges parsed in from the input
   */
  public DotParser(Reader input, ArrayList nodes,
    ArrayList edges) {
    m_nodes = nodes;
    m_edges = edges;
    m_input = input;
  }

  /**
   * This method parses the string or the InputStream that we passed in through
   * the constructor and builds up the m_nodes and m_edges vectors
   * 
   * @return - returns the name of the graph
   */
  public String parse() {
    StreamTokenizer tk = new StreamTokenizer(new BufferedReader(m_input));
    setSyntax(tk);

    graph(tk);

    return m_graphName;
  }

  /**
   * This method sets the syntax of the StreamTokenizer. i.e. set the
   * whitespace, comment and delimit chars.
   * 
   */
  protected void setSyntax(StreamTokenizer tk) {
    tk.resetSyntax();
    tk.eolIsSignificant(false);
    tk.slashStarComments(true);
    tk.slashSlashComments(true);
    tk.whitespaceChars(0, ' ');
    tk.wordChars(' ' + 1, '\u00ff');
    tk.ordinaryChar('[');
    tk.ordinaryChar(']');
    tk.ordinaryChar('{');
    tk.ordinaryChar('}');
    tk.ordinaryChar('-');
    tk.ordinaryChar('>');
    tk.ordinaryChar('/');
    tk.ordinaryChar('*');
    tk.quoteChar('"');
    tk.whitespaceChars(';', ';');
    tk.ordinaryChar('=');
  }

  /*************************************************************
   * 
   * Following methods parse the DOT input and mimic the DOT language's grammar
   * in their structure
   * 
   ************************************************************* 
   */
  protected void graph(StreamTokenizer tk) {
    try {
      tk.nextToken();

      if (tk.ttype == StreamTokenizer.TT_WORD) {
        if (tk.sval.equalsIgnoreCase("digraph")) {
          tk.nextToken();
          if (tk.ttype == StreamTokenizer.TT_WORD) {
            m_graphName = tk.sval;
            tk.nextToken();
          }

          while (tk.ttype != '{') {
            System.err.println("Error at line " + tk.lineno()
              + " ignoring token " + tk.sval);
            tk.nextToken();
            if (tk.ttype == StreamTokenizer.TT_EOF) {
              return;
            }
          }
          stmtList(tk);
        } else if (tk.sval.equalsIgnoreCase("graph")) {
          System.err.println("Error. Undirected graphs cannot be used");
        } else {
          System.err.println("Error. Expected graph or digraph at line "
            + tk.lineno());
        }
      }
    } catch (Exception ex) {
      ex.printStackTrace();
    }

    // int tmpMatrix[][] = new int[m_nodes.size()][m_nodes.size()];
    // for(int i=0; i= 'a' && tk.ttype <= 'z')
      || (tk.ttype >= 'A' && tk.ttype <= 'Z')) {
      if (m_nodes != null && !(m_nodes.contains(new GraphNode(tk.sval, null)))) {
        m_nodes.add(new GraphNode(tk.sval, tk.sval));
        // System.out.println("Added node >"+tk.sval+"<");
      }
    } else {
      throw new Exception();
    }

    // tk.nextToken();
  }

  protected void nodeStmt(StreamTokenizer tk, final int nindex)
    throws Exception {
    tk.nextToken();

    GraphNode temp = m_nodes.get(nindex);

    if (tk.ttype == ']' || tk.ttype == StreamTokenizer.TT_EOF) {
      return;
    } else if (tk.ttype == StreamTokenizer.TT_WORD) {

      if (tk.sval.equalsIgnoreCase("label")) {

        tk.nextToken();
        if (tk.ttype == '=') {
          tk.nextToken();
          if (tk.ttype == StreamTokenizer.TT_WORD || tk.ttype == '"') {
            temp.lbl = tk.sval;
          } else {
            System.err.println("couldn't find label at line " + tk.lineno());
            tk.pushBack();
          }
        } else {
          System.err.println("couldn't find label at line " + tk.lineno());
          tk.pushBack();
        }
      }

      else if (tk.sval.equalsIgnoreCase("color")) {

        tk.nextToken();
        if (tk.ttype == '=') {
          tk.nextToken();
          if (tk.ttype == StreamTokenizer.TT_WORD || tk.ttype == '"') {
            ;
          } else {
            System.err.println("couldn't find color at line " + tk.lineno());
            tk.pushBack();
          }
        } else {
          System.err.println("couldn't find color at line " + tk.lineno());
          tk.pushBack();
        }
      }

      else if (tk.sval.equalsIgnoreCase("style")) {

        tk.nextToken();
        if (tk.ttype == '=') {
          tk.nextToken();
          if (tk.ttype == StreamTokenizer.TT_WORD || tk.ttype == '"') {
            ;
          } else {
            System.err.println("couldn't find style at line " + tk.lineno());
            tk.pushBack();
          }
        } else {
          System.err.println("couldn't find style at line " + tk.lineno());
          tk.pushBack();
        }
      }
    }
    nodeStmt(tk, nindex);
  }

  protected void edgeStmt(StreamTokenizer tk, final int nindex)
    throws Exception {
    tk.nextToken();

    GraphEdge e = null;
    if (tk.ttype == '>') {
      tk.nextToken();
      if (tk.ttype == '{') {
        while (true) {
          tk.nextToken();
          if (tk.ttype == '}') {
            break;
          } else {
            nodeID(tk);
            e = new GraphEdge(nindex, m_nodes.indexOf(new GraphNode(tk.sval,
              null)), DIRECTED);
            if (m_edges != null && !(m_edges.contains(e))) {
              m_edges.add(e);
              // System.out.println("Added edge from "+
              // ((GraphNode)(m_nodes.get(nindex))).ID+
              // " to "+
              // ((GraphNode)(m_nodes.get(e.dest))).ID);
            }
          }
        }
      } else {
        nodeID(tk);
        e = new GraphEdge(nindex,
          m_nodes.indexOf(new GraphNode(tk.sval, null)), DIRECTED);
        if (m_edges != null && !(m_edges.contains(e))) {
          m_edges.add(e);
          // System.out.println("Added edge from "+
          // ((GraphNode)(m_nodes.get(nindex))).ID+" to "+
          // ((GraphNode)(m_nodes.get(e.dest))).ID);
        }
      }
    } else if (tk.ttype == '-') {
      System.err.println("Error at line " + tk.lineno()
        + ". Cannot deal with undirected edges");
      if (tk.ttype == StreamTokenizer.TT_WORD) {
        tk.pushBack();
      }
      return;
    } else {
      System.err.println("Error at line " + tk.lineno() + " in edgeStmt");
      if (tk.ttype == StreamTokenizer.TT_WORD) {
        tk.pushBack();
      }
      return;
    }

    tk.nextToken();

    if (tk.ttype == '[') {
      edgeAttrib(tk, e);
    } else {
      tk.pushBack();
    }
  }

  protected void edgeAttrib(StreamTokenizer tk, final GraphEdge e)
    throws Exception {
    tk.nextToken();

    if (tk.ttype == ']' || tk.ttype == StreamTokenizer.TT_EOF) {
      return;
    } else if (tk.ttype == StreamTokenizer.TT_WORD) {

      if (tk.sval.equalsIgnoreCase("label")) {

        tk.nextToken();
        if (tk.ttype == '=') {
          tk.nextToken();
          if (tk.ttype == StreamTokenizer.TT_WORD || tk.ttype == '"') {
            System.err.println("found label " + tk.sval);// e.lbl = tk.sval;
          } else {
            System.err.println("couldn't find label at line " + tk.lineno());
            tk.pushBack();
          }
        } else {
          System.err.println("couldn't find label at line " + tk.lineno());
          tk.pushBack();
        }
      } else if (tk.sval.equalsIgnoreCase("color")) {

        tk.nextToken();
        if (tk.ttype == '=') {
          tk.nextToken();
          if (tk.ttype == StreamTokenizer.TT_WORD || tk.ttype == '"') {
            ;
          } else {
            System.err.println("couldn't find color at line " + tk.lineno());
            tk.pushBack();
          }
        } else {
          System.err.println("couldn't find color at line " + tk.lineno());
          tk.pushBack();
        }
      }

      else if (tk.sval.equalsIgnoreCase("style")) {

        tk.nextToken();
        if (tk.ttype == '=') {
          tk.nextToken();
          if (tk.ttype == StreamTokenizer.TT_WORD || tk.ttype == '"') {
            ;
          } else {
            System.err.println("couldn't find style at line " + tk.lineno());
            tk.pushBack();
          }
        } else {
          System.err.println("couldn't find style at line " + tk.lineno());
          tk.pushBack();
        }
      }
    }
    edgeAttrib(tk, e);
  }

  /**
   * 
   * This method saves a graph in a file in DOT format. However, if reloaded in
   * GraphVisualizer we would need to layout the graph again.
   * 
   * @param filename - The name of the file to write in. (will overwrite)
   * @param graphName - The name of the graph
   * @param nodes - Vector containing all the nodes
   * @param edges - Vector containing all the edges
   */
  public static void writeDOT(String filename, String graphName,
    ArrayList nodes, ArrayList edges) {
    try {
      FileWriter os = new FileWriter(filename);
      os.write("digraph ", 0, ("digraph ").length());
      if (graphName != null) {
        os.write(graphName + " ", 0, graphName.length() + 1);
      }
      os.write("{\n", 0, ("{\n").length());

      GraphEdge e;
      for (int i = 0; i < edges.size(); i++) {
        e = edges.get(i);
        os.write(nodes.get(e.src).ID, 0, nodes.get(e.src).ID.length());
        os.write("->", 0, ("->").length());
        os.write(nodes.get(e.dest).ID + "\n", 0,
          nodes.get(e.dest).ID.length() + 1);
      }
      os.write("}\n", 0, ("}\n").length());
      os.close();
    } catch (IOException ex) {
      ex.printStackTrace();
    }
  }

} // DotParser




© 2015 - 2024 Weber Informatics LLC | Privacy Policy