MOA 12.03
Real Time Analytics for Data Streams
Plot.java
Go to the documentation of this file.
00001 /*
00002  *    Plot.java
00003  *    Copyright (C) 2010 Poznan University of Technology, Poznan, Poland
00004  *    @author Dariusz Brzezinski (dariusz.brzezinski@cs.put.poznan.pl)
00005  *
00006  *    This program is free software; you can redistribute it and/or modify
00007  *    it under the terms of the GNU General Public License as published by
00008  *    the Free Software Foundation; either version 3 of the License, or
00009  *    (at your option) any later version.
00010  *
00011  *    This program is distributed in the hope that it will be useful,
00012  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *    GNU General Public License for more details.
00015  *
00016  *    You should have received a copy of the GNU General Public License
00017  *    along with this program. If not, see <http://www.gnu.org/licenses/>.
00018  *    
00019  */
00020 package moa.tasks;
00021 
00022 import java.io.BufferedReader;
00023 import java.io.BufferedWriter;
00024 import java.io.File;
00025 import java.io.FileWriter;
00026 import java.io.IOException;
00027 import java.io.InputStreamReader;
00028 
00029 import moa.core.ObjectRepository;
00030 import moa.options.FileOption;
00031 import moa.options.FlagOption;
00032 import moa.options.IntOption;
00033 import moa.options.ListOption;
00034 import moa.options.MultiChoiceOption;
00035 import moa.options.StringOption;
00036 
00043 public class Plot extends MainTask {
00044     @Override
00045     public String getPurposeString() {
00046         return "Creates a Gnuplot script and plots a chart from a set of given csv files.";
00047     }
00048 
00049     private static final long serialVersionUID = 1L;
00050 
00054     public StringOption gnuplotPathOption = new StringOption("gnuplotPath", 'e',
00055             "Directory of the gnuplot executable. For example \"C:\\Tools\\Gnuplot\\binary\".", "");
00056 
00057     
00061     public FileOption plotOutputOption = new FileOption("plotOutputFile", 'r',
00062             "File with the result plot (image).", null, "eps", true);
00063 
00068     public ListOption inputFilesOption = new ListOption(
00069             "inputFiles",
00070             'i',
00071             "File names or file paths of csv inputs. Values should be seperated by commas.",
00072             new StringOption("inputFile", ' ', "Input file.", "algorithm.csv"),
00073             new StringOption[] {
00074                     new StringOption("", ' ', "", "algorithm1.csv"),
00075                     new StringOption("", ' ', "", "algorithm2.csv"),
00076                     new StringOption("", ' ', "", "algorithm3.csv") }, ',');
00077 
00082     public ListOption fileAliasesOption = new ListOption(
00083             "aliases",
00084             'a',
00085             "Aliases for files stated in the inputFiles parameter. Aliases will be presented in the plot's legend.",
00086             new StringOption("alias", ' ', "File alias.", "MyAlg"),
00087             new StringOption[] { new StringOption("", ' ', "", "OZABag"),
00088                     new StringOption("", ' ', "", "HOT"),
00089                     new StringOption("", ' ', "", "AWE") }, ',');
00090 
00094     public MultiChoiceOption outputTypeOption = new MultiChoiceOption(
00095             "outputType", 't', "Gnuplot output terminal.", Terminal
00096                     .getStringValues(), Terminal.getDescriptions(), 8);
00097 
00101     public MultiChoiceOption plotStyleOption = new MultiChoiceOption(
00102             "plotStyle", 'p', "Plot style.", PlotStyle.getStringValues(),
00103             PlotStyle.getDescriptions(), 2);
00104 
00108     public IntOption xColumnOption = new IntOption(
00109             "xColumn",
00110             'x',
00111             "Index of the csv column from which values for the x-axis should be taken.",
00112             1);
00113 
00117     public StringOption xTitleOption = new StringOption("xTitle", 'm',
00118             "Title of the plots' x-axis.", "Processed instances");
00119 
00123     public StringOption xUnitOption = new StringOption("xUnit", 'g',
00124             "Units displayed next to x-axis values.", "");
00125 
00129     public IntOption yColumnOption = new IntOption(
00130             "yColumn",
00131             'y',
00132             "Index of the column from which values for the y-axis should be taken",
00133             9);
00134 
00138     public StringOption yTitleOption = new StringOption("yTitle", 'n',
00139             "Title of the plots' y-axis.", "Accuracy");
00140 
00144     public StringOption yUnitOption = new StringOption("yUnit", 'u',
00145             "Units displayed next to y-axis values.", "%");
00146 
00150     public IntOption lineWidthOption = new IntOption("lineWidth", 'w',
00151             "Determines the thickness of plotted lines", 2);
00152 
00156     public IntOption pointIntervalOption = new IntOption(
00157             "pointInterval",
00158             'v',
00159             "Determines the inteval between plotted data points. Used for LINESPOINTS plots only.",
00160             0, 0, Integer.MAX_VALUE);
00164     public FlagOption smoothOption = new FlagOption("smooth", 's',
00165             "Determines whether to smooth the plot with bezier curves.");
00169     public FlagOption deleteScriptsOption = new FlagOption("deleteScripts",
00170             'd', "Determines whether to delete gnuplot scripts after plotting.");
00171 
00175     public MultiChoiceOption legendLocationOption = new MultiChoiceOption(
00176             "legendLocation", 'l', "Legend (key) location on the plot.",
00177             LegendLocation.getStringValues(), LegendLocation.getDescriptions(),
00178             8);
00179 
00183     public MultiChoiceOption legendTypeOption = new MultiChoiceOption(
00184             "legendType", 'k', "Legend elements' alignment.", LegendType
00185                     .getStringValues(), LegendType.getDescriptions(), 1);
00186 
00192     public StringOption additionalSetOption = new StringOption(
00193             "additionalCommands",
00194             'c',
00195             "Additional commands that should be added to the gnuplot script before the plot command. For example \"set tics out\" will change the default tic option and force outward facing tics. See the gnuplot manual for more commands.",
00196             " ");
00197 
00202     public StringOption additionalPlotOption = new StringOption(
00203             "additionalPlotOptions",
00204             'z',
00205             "Additional options that should be added to the gnuplot script in the plot statement. For example \"[] [0:]\" will force the y-axis to start from 0. See the gnuplot manual for more options.",
00206             " ");
00207 
00213     public enum Terminal {
00214         CANVAS, EPSLATEX, GIF, JPEG, LATEX, PDFCAIRO, PNG, POSTSCRIPT, POSTSCRIPT_COLOR, PSLATEX, PSTEX, PSTRICKS, SVG;
00215 
00216         private static String[] descriptions = new String[] {
00217                 "HTML Canvas object",
00218                 "LaTeX picture environment using graphicx package",
00219                 "GIF images using libgd and TrueType fonts",
00220                 "JPEG images using libgd and TrueType fonts",
00221                 "LaTeX picture environment",
00222                 "pdf terminal based on cairo",
00223                 "PNG images using libgd and TrueType fonts",
00224                 "PostScript graphics, including EPSF embedded files (*.eps)",
00225                 "Color PostScript graphics, including EPSF embedded files (*.eps)",
00226                 "LaTeX picture environment with PostScript specials",
00227                 "plain TeX with PostScript specials",
00228                 "LaTeX picture environment with PSTricks macros",
00229                 "W3C Scalable Vector Graphics driver" };
00230 
00235         public static String[] getDescriptions() {
00236             return descriptions;
00237         }
00238 
00243         public static String[] getStringValues() {
00244             int i = 0;
00245             String[] result = new String[values().length];
00246 
00247             for (Terminal value : values()) {
00248                 result[i++] = value.name();
00249             }
00250 
00251             return result;
00252         }
00253     }
00254 
00260     public enum LegendLocation {
00261         TOP_LEFT_INSIDE, TOP_CENTER_INSIDE, TOP_RIGHT_INSIDE, LEFT_INSIDE, CENTER_INSIDE, RIGHT_INSIDE, BOTTOM_LEFT_INSIDE, BOTTOM_CENTER_INSIDE, BOTTOM_RIGHT_INSIDE, TOP_LEFT_OUTSIDE, TOP_CENTER_OUTSIDE, TOP_RIGHT_OUTSIDE, LEFT_OUTSIDE, CENTER_OUTSIDE, RIGHT_OUTSIDE, BOTTOM_LEFT_OUTSIDE, BOTTOM_CENTER_OUTSIDE, BOTTOM_RIGHT_OUTSIDE;
00262 
00267         public static String[] getDescriptions() {
00268             int i = 0;
00269             String[] result = new String[values().length];
00270 
00271             for (LegendLocation value : values()) {
00272                 result[i++] = value.name().toLowerCase().replace('_', ' ');
00273             }
00274 
00275             return result;
00276         }
00277 
00282         public static String[] getStringValues() {
00283             int i = 0;
00284             String[] result = new String[values().length];
00285 
00286             for (LegendLocation value : values()) {
00287                 result[i++] = value.name();
00288             }
00289 
00290             return result;
00291         }
00292     }
00293 
00299     public enum LegendType {
00300         NONE, BOX_VERTICAL, BOX_HORIZONTAL, NOBOX_VERTICAL, NOBOX_HORIZONTAL;
00301 
00306         public static String[] getDescriptions() {
00307             int i = 0;
00308             String[] result = new String[values().length];
00309 
00310             for (LegendType value : values()) {
00311                 result[i++] = value.name().toLowerCase().replace('_', ' ');
00312             }
00313 
00314             return result;
00315         }
00316 
00321         public static String[] getStringValues() {
00322             int i = 0;
00323             String[] result = new String[values().length];
00324 
00325             for (LegendType value : values()) {
00326                 result[i++] = value.name();
00327             }
00328 
00329             return result;
00330         }
00331     }
00332 
00333     public enum PlotStyle {
00334         LINES, POINTS, LINESPOINTS, IMPULSES, STEPS, FSTEPS, HISTEPS, DOTS;
00335 
00336         private static String[] descriptions = new String[] {
00337                 "It connects each data point with lines. Suitable to smoothly varying data.",
00338                 "Symbols are shown at the data point location, can be used to plot experimental data.",
00339                 "Draws lines and symbols at the same time.",
00340                 "Draw vertical lines from each data point to X-axis. This is a bar-graph without width.",
00341                 "Histogram type 1",
00342                 "Histogram type 2",
00343                 "Histogram type 3",
00344                 "It displays dots, can be used when there many data points, but hard to see though.", };
00345 
00350         public static String[] getDescriptions() {
00351             return descriptions;
00352         }
00353 
00358         public static String[] getStringValues() {
00359             int i = 0;
00360             String[] result = new String[values().length];
00361 
00362             for (PlotStyle value : values()) {
00363                 result[i++] = value.name();
00364             }
00365 
00366             return result;
00367         }
00368     }
00369 
00373     public Class<?> getTaskResultType() {
00374         return String.class;
00375     }
00376 
00377     @Override
00378     protected Object doMainTask(TaskMonitor monitor, ObjectRepository repository) {
00379         File resultFile = this.plotOutputOption.getFile();
00380         if (this.plotOutputOption.getFile() == null) {
00381             throw new RuntimeException("Plot output file option not set!");
00382         }
00383 
00384         String resultDirectory = (new File(resultFile.getAbsolutePath()))
00385                 .getParent();
00386         String gnuPlotPath = gnuplotPathOption.getValue();
00387         File gnuplotDir = new File(gnuPlotPath);
00388         if(!gnuplotDir.exists()){
00389             throw new RuntimeException("Gnuplot directory not found: " + gnuPlotPath);
00390         }
00391 
00392         monitor.setCurrentActivity("Verifying input files...", 0.0);
00393 
00394         if (inputFilesOption.getList().length > fileAliasesOption.getList().length) {
00395             throw new RuntimeException("Too little aliases for input files!");
00396         } else if (inputFilesOption.getList().length < fileAliasesOption
00397                 .getList().length) {
00398             throw new RuntimeException("Too many aliases for input files!");
00399         } else {
00400             for (int i = 0; i < inputFilesOption.getList().length; i++) {
00401                 File inputFile = new File(((StringOption) inputFilesOption
00402                         .getList()[i]).getValue());
00403 
00404                 if (!inputFile.exists()) {
00405                     throw new RuntimeException("File not found: "
00406                             + inputFile.getAbsolutePath());
00407                 }
00408             }
00409         }
00410 
00411         if (monitor.taskShouldAbort()) {
00412             return null;
00413         }
00414         monitor.setCurrentActivity("Creating script file...", 1.0 / 4.0);
00415 
00416         String gnuplotScriptPath = resultDirectory + File.separator
00417                 + resultFile.getName() + ".plt";
00418         String script = createScript(resultFile);
00419         File scriptFile = writeScriptToFile(gnuplotScriptPath, script);
00420 
00421         if (monitor.taskShouldAbort()) {
00422             return null;
00423         }
00424         monitor.setCurrentActivity("Plotting data...", 2.0 / 4.0);
00425 
00426         String gnuplotCommand = gnuPlotPath + File.separator + "gnuplot \""
00427                 + gnuplotScriptPath + "\"";
00428 
00429         String line, gnuplotOutput = "";
00430         try {
00431             Process p = Runtime.getRuntime().exec(gnuplotCommand);
00432 
00433             BufferedReader err = new BufferedReader(new InputStreamReader(p
00434                     .getErrorStream()));
00435             while ((line = err.readLine()) != null) {
00436                 gnuplotOutput += line + System.getProperty("line.separator");
00437             }
00438             err.close();
00439         } catch (IOException ex) {
00440             throw new RuntimeException("Error while executing gnuplot script:"
00441                     + scriptFile, ex);
00442         }
00443 
00444         if (monitor.taskShouldAbort()) {
00445             return null;
00446         }
00447         if (deleteScriptsOption.isSet()) {
00448             monitor.setCurrentActivity("Deleting script...", 3.0 / 4.0);
00449             scriptFile.delete();
00450         }
00451         if (monitor.taskShouldAbort()) {
00452             return null;
00453         }
00454         monitor.setCurrentActivity("Done", 1.0);
00455 
00456         return resultFile.getAbsolutePath()
00457                 + System.getProperty("line.separator") + gnuplotOutput;
00458     }
00459 
00466     private File writeScriptToFile(String gnuplotScriptPath, String script) {
00467         File scriptFile = new File(gnuplotScriptPath);
00468         BufferedWriter writer;
00469         try {
00470             writer = new BufferedWriter(new FileWriter(scriptFile));
00471             writer.write(script);
00472             writer.close();
00473         } catch (IOException ex) {
00474             throw new RuntimeException(
00475                     "Unable to create or write to script file: " + scriptFile,
00476                     ex);
00477         }
00478         return scriptFile;
00479     }
00480 
00486     private String createScript(File resultFile) {
00487         String newLine = System.getProperty("line.separator");
00488         int sourceFileIdx = 0;
00489 
00490         // terminal options;
00491         String script = "set term "
00492                 + terminalOptions(Terminal.valueOf(outputTypeOption
00493                         .getChosenLabel())) + newLine;
00494         script += "set output '" + resultFile.getAbsolutePath() + "'" + newLine;
00495         script += "set datafile separator ','" + newLine;
00496         script += "set grid" + newLine;
00497         script += "set style line 1 pt 8" + newLine;
00498         script += "set style line 2 lt rgb '#00C000'" + newLine;
00499         script += "set style line 5 lt rgb '#FFD800'" + newLine;
00500         script += "set style line 6 lt rgb '#4E0000'" + newLine;
00501         script += "set format x '%.0s %c" + getAxisUnit(xUnitOption.getValue())
00502                 + "'" + newLine;
00503         script += "set format y '%.0s %c" + getAxisUnit(yUnitOption.getValue())
00504                 + "'" + newLine;
00505         script += "set ylabel '" + yTitleOption.getValue() + "'" + newLine;
00506         script += "set xlabel '" + xTitleOption.getValue() + "'" + newLine;
00507         if (!legendTypeOption.getChosenLabel().equals(LegendType.NONE)) {
00508             script += "set key "
00509                     + legendTypeOption.getChosenLabel().toLowerCase().replace(
00510                             '_', ' ')
00511                     + " "
00512                     + legendLocationOption.getChosenLabel().toLowerCase()
00513                             .replace('_', ' ') + newLine;
00514         }
00515 
00516         // additional commands
00517         script += additionalSetOption.getValue();
00518 
00519         // plot command
00520         script += "plot " + additionalPlotOption.getValue() + " ";
00521 
00522         // plot for each input file
00523         for (int i = 0; i < inputFilesOption.getList().length; i++) {
00524                 
00525             if (sourceFileIdx > 0) {
00526                 script += ", ";
00527             }
00528             sourceFileIdx++;
00529             script += "'" + ((StringOption) inputFilesOption
00530                         .getList()[i]).getValue() + "' using "
00531                     + xColumnOption.getValue() + ":" + yColumnOption.getValue();
00532 
00533             if (smoothOption.isSet()) {
00534                 script += ":(1.0) smooth bezier";
00535             }
00536 
00537             script += " with " + plotStyleOption.getChosenLabel().toLowerCase()
00538                     + " ls " + sourceFileIdx + " lw "
00539                     + lineWidthOption.getValue();
00540             if (plotStyleOption.getChosenLabel().equals(
00541                     PlotStyle.LINESPOINTS.toString())
00542                     && pointIntervalOption.getValue() > 0) {
00543                 script += " pointinterval " + pointIntervalOption.getValue();
00544             }
00545             script += " title '" + ((StringOption) fileAliasesOption
00546                         .getList()[i]).getValue() + "'";
00547         }
00548         script += newLine;
00549         return script;
00550     }
00551 
00552     private String getAxisUnit(String unit) {
00553         if (unit.equals("%")) {
00554             return "%%";
00555         } else {
00556             return unit;
00557         }
00558     }
00559 
00560     private String terminalOptions(Terminal term) {
00561         String options;
00562 
00563         switch (term) {
00564         case POSTSCRIPT:
00565             options = "postscript enhanced";
00566             break;
00567         case POSTSCRIPT_COLOR:
00568             options = "postscript color enhanced";
00569             break;
00570         default:
00571             options = term.toString().toLowerCase();
00572             break;
00573         }
00574         return options;
00575     }
00576 }
 All Classes Namespaces Files Functions Variables Enumerations