weka.gui.graphvisualizer.DotParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of weka-stable Show documentation
Show all versions of weka-stable Show documentation
The Waikato Environment for Knowledge Analysis (WEKA), a machine
learning workbench. This is the stable version. Apart from bugfixes, this version
does not receive any other updates.
/*
* 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