/*
* Copyright 2004-2010 Information & Software Engineering Group (188/1)
* Institute of Software Technology and Interactive Systems
* Vienna University of Technology, Austria
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.ifs.tuwien.ac.at/dm/somtoolbox/license.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package at.tuwien.ifs.somtoolbox.reportgenerator.output;
import java.io.File;
import at.tuwien.ifs.somtoolbox.reportgenerator.DatasetInformation;
import at.tuwien.ifs.somtoolbox.reportgenerator.TestRunResult;
import at.tuwien.ifs.somtoolbox.reportgenerator.TestRunResultCollection;
import at.tuwien.ifs.somtoolbox.reportgenerator.TextualDescriptionProvider;
import at.tuwien.ifs.somtoolbox.util.StringUtils;
/**
* This class generates the Report as LATEX output. It holds a reference to an instance of ReportFileWriter, to which
* all Strings that shall appear in the output are send. This class does only handle how this strings schall look like,
* and not with any technical detail about how these strings are actually written to a file or elsewhere.
*
* @author Sebastian Skritek (0226286, Sebastian.Skritek@gmx.at)
* @author Martin Waitzbauer (0226025)
* @version $Id: OutputReportLATEX.java 3883 2010-11-02 17:13:23Z frank $
*/
public class OutputReportLATEX implements OutputReport {
/** handles the actual writing of the output. All Strings that shall appear in the output are handed over to it */
private ReportFileWriter writer;
private DatasetInformation datasetInformation;
private TestRunResultCollection testruns;
private String outputDirPath = "";
private int type;
/**
* Creates a new Object to finally print the report in LATEX
*
* @param outputDir the path to the directory where the files shall be saved to
*/
public OutputReportLATEX(String outputDir) {
if (!outputDir.endsWith(System.getProperty("file.separator"))) {
outputDir += System.getProperty("file.separator");
}
this.writer = new ReportFileWriter(outputDir + "report.tex", 2);
this.outputDirPath = outputDir;
}
/**
* gives an Object to the report writer that stores all information about the used dataset. Should be specified
* before the createOutput function is called, otherwise no information about the dataset can be reported
*
* @param infoObj object containing all available information about the used dataset
*/
@Override
public void setDatasetInformation(DatasetInformation infoObj) {
this.datasetInformation = infoObj;
}
/**
* gives an Object to the report writer that stores all information about the performed that shall be documented
* within the report. Should be specified before the createOutput function is called, otherwise no information about
* the testruns can be reported
*
* @param testruns object containting all available information about the testruns performed
*/
@Override
public void setTestrunInformation(TestRunResultCollection testruns, int type) {
this.testruns = testruns;
this.type = type;
}
/**
* creates the report about as HTML file. All necessary setXXX functions should be called before this function is
* called and the output starts.
*/
@Override
public void createOutput() {
System.out.println("HIER");
this.printReportStart();
if (this.datasetInformation != null) {
this.printDatasetReport();
}
if (this.testruns != null && this.testruns.getNumberOfRuns() > 0) {
this.printTestrunsReport();
}
this.printReportEnd();
}
/**
* prints the head of the report this includes the title and all tags or markup required at the beginning of the
* report
*/
private void printReportStart() {
this.writer.appendOutput("%neuer Befehl: \\includegraphicstotab[..]{..}\n"
+ "\\newlength{\\myx} % Variable zum Speichern der Bildbreite\n"
+ "\\newlength{\\myy} % Variable zum Speichern der Bildhöhe\n"
+ "\\newcommand\\includegraphicstotab[2][\\relax]{%\n" + "% Abspeichern der Bildabmessungen\n"
+ "\\settowidth{\\myx}{\\includegraphics[{#1}]{#2}}%\n"
+ "\\settoheight{\\myy}{\\includegraphics[{#1}]{#2}}%\n" + "% das eigentliche Einfügen\n"
+ "\\parbox[c][1.1\\myy][c]{\\myx}{%\n" + "\\includegraphics[{#1}]{#2}}%\n" + "}% Ende neuer Befehl\n"
+ "\\documentclass[a4paper,10pt]{article}\n" + "\\usepackage{longtable}\n" + "\\usepackage{color}\n"
+ "\\usepackage{colortbl}\n" + "%Definiere die Tabellenfarben\n");
/* Definiere die Tabellenfarben */
for (int i = 0; i < this.datasetInformation.getNumberOfClasses(); i++) {
String CurrClassColor = StringUtils.getLatexRGBString(this.datasetInformation.getClassColorRGB(i));
this.writer.appendOutput("\\definecolor{" + CurrClassColor + "}{rgb}{");
this.writer.appendOutput(StringUtils.getLatexRGBString(this.datasetInformation.getClassColorRGB(i)) + "}");
}
this.writer.appendOutput("%ENDE FARBDEFINITION");
this.writer.appendOutput("\\usepackage{amsmath}\n" + "\\usepackage{graphics}\n" + "\\usepackage{rotating}\n"
+ "\\voffset -3.9cm\n" + "\\hoffset -2.6cm\n" + "\\oddsidemargin 1.5cm\n" + "\\evensidemargin 0cm\n"
+ "\\topmargin 2.5cm\n" + "\\headsep 0pt\n" + "\\headheight 0pt\n" + "\\textheight 24.2cm\n"
+ "\\textwidth 18.5cm\n" + "\\title{Automatically generated Report for the SOM}\n" + "\\author{}\n"
+ "\\begin{document}\n" + "\\maketitle\n" + "\\begin{abstract}\n"
+ "\\begin{center}This is an automatically generated report about the training of a SOM.\n"
+ "This Report is based on Data Records in the Files:\\\\\n");
String[] filenames = new String[] { "Input Vector File:", "Template Vector File:", "Class information File:" };
for (int i = 0; i < filenames.length; i++) {
this.writer.appendOutput("\\textbf{" + filenames[i] + "} "
+ this.datasetInformation.getTrainingDataInfo()[i] + "\\\\\n");
}
this.writer.appendOutput("\\end{center}\n" + "\\end{abstract}\n");
/* Inhaltsverzeichnis erstellen */
this.writer.appendOutput("\\tableofcontents");
}
/**
* prints the foot of the report this includes any fixed data to be displayed at the end, as well as all markup
* required to finish and close the report
*/
private void printReportEnd() {
this.writer.appendLatexOutput("\\end{document}");
this.writer.finish();
}
/**
* outputs the section concerning the dataset Information included in this section are:
* <ul>
* <li>number of inputs</li>
* <li>dimension of inputs</li>
* <li>information about the data distribution within the different dimensions</li>
* <li>...</li>
* </ul>
* Also, if class information are provided, these are printed. This includes: the number of classes, the number of
* inputs within each class, ...
*/
private void printDatasetReport() {
// header
double[][] dim_array = this.datasetInformation.getPCAdeterminedDims(); /*
* Get the Array with the most important Dims, ordered decreasingly by
* importance
*/
/*
* Here we calculate how many Dimensions are still "left over" so to say, that is, which ones have not been visualized due to their small
* importance. Anyway we want to see how many dimensions share what remaining Percentage of the total variance
*/
double perc = this.datasetInformation.calculateAccumulatedVariance();
String pca_desc = TextualDescriptionProvider.getScientificDescription("pca");
this.writer.appendLatexOutput("\\section{The Dataset}\n");
this.writer.appendLatexOutput("This section describes the dataset that was used for training the SOM, and therefore shall be represented by the SOM.\n"
+ "After some general information, a closer look is taken onto each dimension of the input vectors. Input Vectors are chosen according to the results"
+ "of a " + pca_desc);
if (dim_array.length == 5) { /* Dim_array == 5 , if the Dim vector had more than 5 dimensions */
this.writer.appendOutput(" The remaining " + (this.datasetInformation.getVectorDim() - dim_array.length)
+ " " + "dimensions that are not displayed share an accumulated Variance of "
+ String.format("%.2f", 100.0 - perc * 100) + "\\%.");
}
if (this.datasetInformation.classInfoAvailable()) {
this.writer.appendLatexOutput("\\\\At the end of this section, some information about the existing classes and how the input items are distributed on them "
+ "are given.");
}
// Information about the input data vectors:
this.writer.appendLatexOutput("\\paragraph{Dataset:\\\\}\n");
this.writer.appendLatexOutput("Number of input vectors: " + datasetInformation.getNumberOfInputVectors()
+ "\\\\\n");
this.writer.appendLatexOutput("Dimensionality of input vectors: " + datasetInformation.getVectorDim()
+ "\\\\\n");
this.writer.appendLatexOutput("Dataset has been normalized: "
+ StringUtils.formatBooleanValue(0, this.datasetInformation.isNormalized()) + "\\\\\n");
this.writer.appendLatexOutput("Number of Classes: " + this.classNumberString() + "\\\\\n");
this.writer.appendLatexOutput("\\paragraph{Attribute details\\\\}\n"
+ "Table 1 on page \\pageref{tab:attdetails} gives an Overview over the Attributes of the Vectors of the trained SOM. The table contains Statistical Base "
+ "numbers and the Variance. The Vectors are shown in decreasing Importance, according to the Results of the PCA.");
this.writer.appendLatexOutput("\\begin{sidewaystable}\n\\begin{tabular}{lccccccccc}\n"
+ "\\textit{label} &\n"
+ "\\textit{Min} &\n"
+ "\\textit{Max} &\n"
+ "\\textit{Mean} &\n"
+ "\\textit{Variance} &\n"
+ "\\textit{# of zeros} &\n"
+ "\\textit{Discr. values} &\n"
+ "\\textit{only $0/1$ values} &\n \\textit{% of total Variance} &\n \\textit{Metro Map Component}\\\\\n");
for (int i = (int) dim_array[0][0], counter = 0; counter < dim_array.length; counter++, i = counter < dim_array.length
? (int) dim_array[counter][0] : (int) dim_array[0][0]) {
this.writer.appendLatexOutput(this.datasetInformation.getAttributeLabel(i) + "&\n");
this.writer.appendLatexOutput(String.format("%.3f", this.datasetInformation.getNumericalDataProps(
DatasetInformation.MIN_VALUE, i))
+ "&\n");
this.writer.appendLatexOutput(String.format("%.3f", this.datasetInformation.getNumericalDataProps(
DatasetInformation.MAX_VALUE, i))
+ "&\n");
this.writer.appendLatexOutput(String.format("%.5f", this.datasetInformation.getNumericalDataProps(
DatasetInformation.MEAN_VALUE, i))
+ "&\n");
this.writer.appendLatexOutput(String.format("%.5f", this.datasetInformation.getNumericalDataProps(
DatasetInformation.VAR_VALUE, i))
+ "&\n");
this.writer.appendLatexOutput((int) this.datasetInformation.getNumericalDataProps(
DatasetInformation.ZERO_VALUE, i)
+ " ("
+ String.format("%.2f", this.datasetInformation.getNumericalDataProps(
DatasetInformation.ZERO_VALUE, i)
/ this.datasetInformation.getNumberOfInputVectors() * 100) + "%)" + "&\n");
this.writer.appendLatexOutput(StringUtils.formatBooleanValue(0, datasetInformation.getBoolDataProps(
DatasetInformation.DISCRETE, i))
+ "&\n");
this.writer.appendLatexOutput(StringUtils.formatBooleanValue(0, datasetInformation.getBoolDataProps(
DatasetInformation.ONLY01, i))
+ "&\n" + String.format("%.2f", dim_array[counter][1] * 100) + " % &\n");
testruns.getRun(0).createSingleMetroMapComponentImage(
this.outputDirPath + SOMDescriptionHTML.imgSubdir + File.separator,
i + "_SingleMetroMapComponent.jpg", i);
this.writer.appendLatexOutput("\\includegraphics[width=50pt]{" + SOMDescriptionHTML.imgSubdir
+ "/component_" + i + "_SingleMetroMapComponent.jpg}\\\\");
}
this.writer.appendLatexOutput("\\end{tabular}\n\\caption{Attribute Details}\n\\label{tab:attdetails}\n\\end{sidewaystable}");
// more detailed class information
if (this.datasetInformation.getNumberOfClasses() > 0) {
this.writer.appendLatexOutput("\\subsection{Class details:}\n"
+ "Table 2 on page \\pageref{tab:classdetails} gives a closer numerical look to the distribution of all classes on the Map.It lists how many input items belong to "
+ "the specific class, aswell as the total absolute percentage of how many input items belong to this class. The uttemrost right"
+ "colum displays the Color used for this Class in some other Visualisations.");
this.writer.appendLatexOutput("\\begin{longtable}{lccl}\n" + "Class label&\n" + "Number of Classmembers&\n"
+ "% of input belong to&\n" + "Class colour used\\\\\n");
for (int i = 0; i < this.datasetInformation.getNumberOfClasses(); i++) {
this.writer.appendLatexOutput(this.datasetInformation.getNameOfClass(i) + "&\n");
this.writer.appendLatexOutput(this.datasetInformation.getNumberOfClassmembers(i) + "&\n");
this.writer.appendLatexOutput(String.format("%.2f",
(double) this.datasetInformation.getNumberOfClassmembers(i)
/ (double) this.datasetInformation.getNumberOfInputVectors() * 100)
+ "%&\n");
this.writer.appendLatexOutput("\\cellcolor{"
+ StringUtils.getLatexRGBString(this.datasetInformation.getClassColorRGB(i)) + "}\\\\\n");
}
this.writer.appendLatexOutput("\\caption{Class Details}\n" + "\\label{tab:classdetails}"
+ "\\end{longtable}\n");
}
}
/**
* first outputs the section containing the results from the different teststruns specified, then a short comparison
* of the testruns (SOM configuration and basic results) is printed. for the output of the sections for the
* different training runs, this.printReportOnTestrun(run) is used
*/
private void printTestrunsReport() {
// header
if (this.testruns.getNumberOfRuns() > 1) {
this.writer.appendLatexOutput("\\section{Results of the SOM trainings}\n");
this.writer.appendLatexOutput("In this section, details about the different specified trainings and their results are "
+ "presented. For each training,");
} else {
this.writer.appendLatexOutput("\\section{Results of the SOM training}\n");
this.writer.appendLatexOutput("In this section, details about the training and the resuling SOM are "
+ "presented. Therefore,");
}
this.writer.appendLatexOutput(" first some basic properties describing the training parameters and the resulting "
+ "SOM are given. Then, the distribution of the input data on the trained SOM is described. This includes the quantization and "
+ "topographic errors existing on the map.");
if (this.datasetInformation.classInfoAvailable()) {
this.writer.appendLatexOutput("\\\\Together with the distribution of the input data items, also information about how and where the classes"
+ " are distributed on the map are given.");
}
this.writer.appendLatexOutput("\\\\At the end, a selection of 10 clusters (and therefore possibilities to group the unit on the SOM) is described.");
// first print details about the different runs
for (int r = 0; r < this.testruns.getNumberOfRuns(); r++) {
this.printReportOnTestrun(r, this.testruns.getNumberOfRuns() > 1);
}
// then print the information retrieved by comparing the runs
if (this.testruns.getNumberOfRuns() > 1) {
this.printComparingReport();
}// otherwise comparing runs would not make any sense
}
/**
* prints the results of/information about one som training and its results. What infromation is actual written to
* the report depends on the type of som that has been trained, as all kind of SOMs may need different information
* to be given. In general, first, a list of parameters for the training process and some basic properties of the
* som are outputted. Then, if a class file has been selected, a table visualizing the class distribution is given.
* If input vectors has been selected for retrieving information about where they are located, another table storing
* these information is printed. After some quantization errors, information about the clusters found are written.
*
* @param r the index of the testrun (start counting by 0)
* @param moreRuns true if the results of more than one training has been spcified, false otherwise
*/
private void printReportOnTestrun(int r, boolean moreRuns) {
if (moreRuns) {
this.writer.appendLatexOutput("\\subsection{" + (r + 1) + ". trained SOM:}\n");
}
this.writer.appendLatexOutput("\\subsection{SOM \\& training properties:}\n");
// to distinguish the different SOMs, we need its idetinfying String
String somtype = (String) this.testruns.getProperty(TestRunResultCollection.keyTopology, r);
SOMDescriptionLATEX somdescr = null;
if (somtype.equals("gg")) {
// growing grid: seems to be produced by GHSOM if no child map is created
somdescr = new SOMGGDescriptionLATEX(this.writer, this.datasetInformation, this.testruns.getRun(r),
this.outputDirPath);
} else if (somtype.equals("ghsom")) {
// a growing hierachical som: has more than one level of soms
somdescr = new SOMGHSOMDescriptionLATEX(this.writer, this.datasetInformation, this.testruns.getRun(r),
this.outputDirPath);
} else {
// mainly GrowingSOM, but we use it also as generic outputter for types with only small differences to
// GrowingSOM
somdescr = new SOMDescriptionLATEX(this.writer, this.datasetInformation, this.testruns.getRun(r),
this.outputDirPath);
}
// now that we have the correct handler for our SOM: handle ;)
somdescr.printSOMDescription();
}
/**
* creates the sections that compares the results of the different specified trainings this comparison constists of
* a table containing some basic properties of the SOMs, the visualizations of the class distribution, the
* distribution of the input items and the U-Matrices of the SOM.
*/
private void printComparingReport() {
writer.appendLatexOutput("\\section{Comparison of the SOMs}\n");
writer.appendLatexOutput("This section tries to compare the SOMs retrieved within the different trainings specified. Therefore, besides a list of the "
+ "basic properties that can be used to describe the training and the SOM, different visualizations are presented.");
// first: a table comparing the basic properties of the SOMs
writer.appendLatexOutput("\\subsubsection{Basic properties of trained SOMs}");
if (testruns.getNumberOfRuns() < 2) {
writer.appendLatexOutput("\\paragraph{Only one run specified, please see the property list for this run}\n");
} else {
// at least two SOMs to compare
writer.appendLatexOutput("\\begin{tabular}{lcccccccc}\n" + "som type&\n" + "dimensions&\n" + "sigma&\n"
+ "tau&\n" + "tau2&\n" + "init learn rate&\n" + "init ngbh. range&\n" + "iterations&\n"
+ "mqe of map\\\\\n");
for (int i = 0; i < this.testruns.getNumberOfRuns(); i++) {
TestRunResult temp = this.testruns.getRun(i);
writer.appendLatexOutput(temp.getMapProperty(TestRunResultCollection.keyTopology) + "&\n");
writer.appendLatexOutput(this.getSOMDimensions(temp) + "&\n");
writer.appendLatexOutput(StringUtils.formatDouble(temp.getSigma()) + "&\n");
writer.appendLatexOutput(StringUtils.formatDouble(temp.getTau()) + "&\n");
writer.appendLatexOutput(StringUtils.formatDouble(temp.getTau2()) + "&\n");
writer.appendLatexOutput(StringUtils.formatString((String) temp.getMapProperty(TestRunResultCollection.keyLearnRateInit))
+ "&\n");
writer.appendLatexOutput(StringUtils.formatString((String) temp.getMapProperty(TestRunResultCollection.keyNeighbourhoodInit))
+ "&\n");
writer.appendLatexOutput(temp.getMapProperty(TestRunResultCollection.keyTotalIterations) + "&\n");
writer.appendLatexOutput(StringUtils.formatDouble(temp.getMapMQE().getQE()) + "\\\\\n");
}
writer.appendLatexOutput("\\end{tabular}");
}
// the next thing are the images showing the class distribution
if (this.datasetInformation.classInfoAvailable()) {
this.writer.appendLatexOutput("\\subsubsection{Class distribution on the trained SOMs}\n");
this.writer.appendLatexOutput("The following images show the distribution of the classes on the trained SOM. Thereby, SOMs having "
+ "different dimensions are displayed in different size. Each unit on the SOM got 10x10 pixel within the image.\\\\\n");
this.writer.appendLatexOutput("\n\\begin{tabular}{");
for (int i = 0; i < this.testruns.getNumberOfRuns(); i++) {
this.writer.appendOutput("l");
}
this.writer.appendOutput("}");
for (int i = 0; i < this.testruns.getNumberOfRuns(); i++) {
TestRunResult temp = this.testruns.getRun(i);
temp.createClassDistributionImage(this.outputDirPath + "images" + System.getProperty("file.separator"),
"classDistribution.jpg", -1);
this.writer.appendOutput("\\includegraphics{images/run_" + temp.getRunId() + "_classDistribution.jpg}");
if (i + 1 < this.testruns.getNumberOfRuns()) {
this.writer.appendOutput("\n&\n");
}
}
this.writer.appendLatexOutput("\\\\\n");
for (int i = 0; i < this.testruns.getNumberOfRuns(); i++) {
this.writer.appendLatexOutput("run " + (i + 1));
if (i + 1 < this.testruns.getNumberOfRuns()) {
this.writer.appendOutput("\n&\n");
}
}
this.writer.appendLatexOutput("\\end{tabular}");
}
// then an image with the comparison of the input data distribution
this.writer.appendLatexOutput("\\subsubsection{Distribution of the input vectors on the trained SOMs}\n");
this.writer.appendLatexOutput("The following images show the distribution of the input vectors on the trained SOM. Green (and other light colors) indicate areas "
+ "where only a small number of input items is mapped to, whereas dark colors mark the areas with more items. "
+ "Again, different sizes of the maps are preserved by the images.\\\\\n");
this.writer.appendLatexOutput("\\begin{tabular}{");
for (int i = 0; i < this.testruns.getNumberOfRuns(); i++) {
this.writer.appendOutput("l");
}
this.writer.appendOutput("}");
for (int i = 0; i < this.testruns.getNumberOfRuns(); i++) {
TestRunResult temp = this.testruns.getRun(i);
temp.createInputDistributionImage(this.outputDirPath + "images" + System.getProperty("file.separator"),
"inputDistribution.jpg");
this.writer.appendOutput("\\includegraphics{images/run_" + temp.getRunId() + "_inputDistribution.jpg}");
if (i + 1 < this.testruns.getNumberOfRuns()) {
this.writer.appendOutput("\n&\n");
}
}
this.writer.appendLatexOutput("\\\\\n");
for (int i = 0; i < this.testruns.getNumberOfRuns(); i++) {
this.writer.appendLatexOutput("run " + (i + 1));
if (i + 1 < this.testruns.getNumberOfRuns()) {
this.writer.appendOutput("\n&\n");
}
}
this.writer.appendLatexOutput("\\end{tabular}");
// the last thing is an image of the umatrix for comparison
this.writer.appendLatexOutput("\\subsubsection{U-Matrices of the trained SOM}");
this.writer.appendLatexOutput("Although an visual description of the U-Matrix of the SOMs is contained in the detail description, to give a "
+ "better possibility to compare them, a smaller version of the images is put here again. \\\\\n"
+ "Therefore, the following images show the distance between neighboured units on the SOM. Again, light areas (especially green) represent"
+ "a small distance between the units, whereas dark colors (especially red) show bigger distances. Like before, different sizes of the "
+ "SOMs are preserved within their representation\\\\\n");
this.writer.appendLatexOutput("\\begin{tabular}{");
for (int i = 0; i < this.testruns.getNumberOfRuns(); i++) {
this.writer.appendOutput("l");
}
this.writer.appendOutput("}");
for (int i = 0; i < this.testruns.getNumberOfRuns(); i++) {
TestRunResult temp = this.testruns.getRun(i);
temp.createUDMatrixImage(this.outputDirPath + "images" + System.getProperty("file.separator"),
"umatrix_small.jpg", 10, 0);
this.writer.appendOutput("\\includegraphics{images/run_" + temp.getRunId() + "_umatrix_small.jpg}");
if (i + 1 < this.testruns.getNumberOfRuns()) {
this.writer.appendOutput("\n&\n");
}
}
this.writer.appendLatexOutput("\\\\\n");
for (int i = 0; i < this.testruns.getNumberOfRuns(); i++) {
this.writer.appendLatexOutput("run " + (i + 1));
if (i + 1 < this.testruns.getNumberOfRuns()) {
this.writer.appendOutput("\n&\n");
}
}
this.writer.appendLatexOutput("\\end{tabular}");
;
}
/**
* returns the dimension of the SOM nicley formatted. returned as string x-size x y- size
*
* @param testrun the testrun for which the dimensions are needed
* @return unknown or "x-size x y-size" (in units)
*/
private String getSOMDimensions(TestRunResult testrun) {
String xunits = (String) testrun.getMapProperty(TestRunResultCollection.keyXDim);
String yunits = (String) testrun.getMapProperty(TestRunResultCollection.keyYDim);
String dim = "unknown";
if (xunits != null && yunits != null) {
dim = xunits + " x " + yunits;
}
return dim;
}
/**
* returns the information (or missing information) about classes nicely formatted
*
* @return the number of classes or information that this information is missing
*/
private String classNumberString() {
if (this.datasetInformation.getNumberOfClasses() < 0) {
return "There are no class information attached to this input";
} else {
return "" + this.datasetInformation.getNumberOfClasses();
}
}
}