From c591f173868ff7561a3a3a3dbcf86ee0655dcc3a Mon Sep 17 00:00:00 2001
From: Richeeyyy <richard.schmidt@mailbox.tu-dresden.de>
Date: Fri, 5 Jul 2019 20:12:08 +0200
Subject: [PATCH] Implement CSV parser, bugfixes TODO

---
 build.gradle                                  |   6 +
 parser_bar.csv                                |  11 +
 parser_line.csv                               |  13 +
 parser_scatter.csv                            |  14 +
 .../java/CsvDataImporter/CsvDataImporter.java |  46 ---
 .../de/tudresden/inf/mci/brailleplot/App.java |  21 +-
 src/main/java/diagrams/BarChart.java          |  12 +
 src/main/java/diagrams/Diagram.java           |  23 ++
 src/main/java/diagrams/LinePlot.java          |  11 +
 src/main/java/diagrams/ScatterPlot.java       |  11 +
 src/main/java/parser/Axis.java                | 151 ++++++++++
 .../java/parser/CategorialPointListList.java  |  69 +++++
 src/main/java/parser/Constants.java           |  46 +++
 src/main/java/parser/CoordinateSystem.java    | 284 ++++++++++++++++++
 src/main/java/parser/CsvDotParser.java        | 130 ++++++++
 src/main/java/parser/CsvOrientation.java      |  34 +++
 src/main/java/parser/CsvParseAlgorithm.java   |  49 +++
 src/main/java/parser/CsvParser.java           |  71 +++++
 src/main/java/parser/CsvType.java             |  52 ++++
 .../parser/CsvXAlignedCategoriesParser.java   | 134 +++++++++
 src/main/java/parser/CsvXAlignedParser.java   | 144 +++++++++
 src/main/java/parser/MetricAxis.java          | 132 ++++++++
 src/main/java/parser/NominalAxis.java         |  88 ++++++
 src/main/java/parser/Point.java               | 242 +++++++++++++++
 src/main/java/parser/PointListList.java       | 245 +++++++++++++++
 src/main/java/parser/Range.java               | 117 ++++++++
 src/main/java/parser/SvgTools.java            | 111 +++++++
 src/main/java/parser/XType.java               |   8 +
 src/main/java/parser/package-info.java        |   4 +
 29 files changed, 2232 insertions(+), 47 deletions(-)
 create mode 100644 parser_bar.csv
 create mode 100644 parser_line.csv
 create mode 100644 parser_scatter.csv
 delete mode 100644 src/main/java/CsvDataImporter/CsvDataImporter.java
 create mode 100644 src/main/java/diagrams/BarChart.java
 create mode 100644 src/main/java/diagrams/Diagram.java
 create mode 100644 src/main/java/diagrams/LinePlot.java
 create mode 100644 src/main/java/diagrams/ScatterPlot.java
 create mode 100644 src/main/java/parser/Axis.java
 create mode 100644 src/main/java/parser/CategorialPointListList.java
 create mode 100644 src/main/java/parser/Constants.java
 create mode 100644 src/main/java/parser/CoordinateSystem.java
 create mode 100644 src/main/java/parser/CsvDotParser.java
 create mode 100644 src/main/java/parser/CsvOrientation.java
 create mode 100644 src/main/java/parser/CsvParseAlgorithm.java
 create mode 100644 src/main/java/parser/CsvParser.java
 create mode 100644 src/main/java/parser/CsvType.java
 create mode 100644 src/main/java/parser/CsvXAlignedCategoriesParser.java
 create mode 100644 src/main/java/parser/CsvXAlignedParser.java
 create mode 100644 src/main/java/parser/MetricAxis.java
 create mode 100644 src/main/java/parser/NominalAxis.java
 create mode 100644 src/main/java/parser/Point.java
 create mode 100644 src/main/java/parser/PointListList.java
 create mode 100644 src/main/java/parser/Range.java
 create mode 100644 src/main/java/parser/SvgTools.java
 create mode 100644 src/main/java/parser/XType.java
 create mode 100644 src/main/java/parser/package-info.java

diff --git a/build.gradle b/build.gradle
index d498333b..4fba8316 100644
--- a/build.gradle
+++ b/build.gradle
@@ -30,6 +30,12 @@ dependencies {
     // Use JUnit test framework
     testImplementation('org.junit.jupiter:junit-jupiter:5.4.2')
     compile "com.opencsv:opencsv:4.0"
+    // https://mvnrepository.com/artifact/com.beust/jcommander
+    compile group: 'com.beust', name: 'jcommander', version: '1.64'
+    // https://mvnrepository.com/artifact/org.slf4j/slf4j-api
+    compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.24'
+
+
 }
 
 test {
diff --git a/parser_bar.csv b/parser_bar.csv
new file mode 100644
index 00000000..17d972b6
--- /dev/null
+++ b/parser_bar.csv
@@ -0,0 +1,11 @@
+{\rtf1\ansi\ansicpg1252\cocoartf1671\cocoasubrtf500
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+{\*\expandedcolortbl;;}
+\paperw11900\paperh16840\margl1440\margr1440\vieww10800\viewh8400\viewkind0
+\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0
+
+\f0\fs24 \cf0 , Reihe a , Reihe b , Reihe c\
+Kat.1 ,3 ,"2 ,5" ,1\
+Kat.2 ,4 ,3 ,2\
+Kat.3 ,"4 ,5" ,3 ,1}
\ No newline at end of file
diff --git a/parser_line.csv b/parser_line.csv
new file mode 100644
index 00000000..b13fd356
--- /dev/null
+++ b/parser_line.csv
@@ -0,0 +1,13 @@
+{\rtf1\ansi\ansicpg1252\cocoartf1671\cocoasubrtf500
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+{\*\expandedcolortbl;;}
+\paperw11900\paperh16840\margl1440\margr1440\vieww10800\viewh8400\viewkind0
+\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0
+
+\f0\fs24 \cf0 Linie1, ,1,7,9,2,10\
+        ,1,2,5,4,10\
+Linie2, ,0,2,7,9,1,4\
+        ,3,9,4,2,5,7\
+\
+}
\ No newline at end of file
diff --git a/parser_scatter.csv b/parser_scatter.csv
new file mode 100644
index 00000000..bd69a608
--- /dev/null
+++ b/parser_scatter.csv
@@ -0,0 +1,14 @@
+{\rtf1\ansi\ansicpg1252\cocoartf1671\cocoasubrtf500
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+{\*\expandedcolortbl;;}
+\paperw11900\paperh16840\margl1440\margr1440\vieww10800\viewh8400\viewkind0
+\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0
+
+\f0\fs24 \cf0 Erste Gruppe,"2,14577671155962","3,83957088149638","2,74381418592686","4,44040259535766","3,05835335915677","3,51347910532925","4,50752129340682","3,10684847076423"\
+,"1,86189289220467","0,845650622246947","1,62491581811196","0,716873892169058","1,07960644510134","1,25420442725184","0,868213570630901","0,3131242131342"\
+Zweite Gruppe,"2,13687514878477","1,0900468273911","0,202664216808808","-0,117994978447507","1,91197730783847","0,472235461102831","1,01858439429409","1,54912208686837"\
+,"0,983807817453276","2,34845526278731","0,785524371519466","0,220854402806683","1,77117365732932","3,01226487117459","-0,327141232914824","-0,210388758733043"\
+Dritte Gruppe,"4,11271848986168","4,99244908180646","5,98316851481515","4,95765061866595","4,00636404848764","5,49799175180235","4,34309770180236","5,36675690932105"\
+,"5,09261289722065","4,92838187744164","4,47540951345638","3,45104975190378","5,64998407245105","4,88914941630864","5,92876353824873","6,67452703834106"\
+}
\ No newline at end of file
diff --git a/src/main/java/CsvDataImporter/CsvDataImporter.java b/src/main/java/CsvDataImporter/CsvDataImporter.java
deleted file mode 100644
index da1f71c1..00000000
--- a/src/main/java/CsvDataImporter/CsvDataImporter.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package CsvDataImporter;
-
-import com.opencsv.CSVReader;
-
-import java.io.IOException;
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.io.FileReader;
-
-
-/**
- * parser for compliant CSV files, creates specified representation of diagram information
- * @author Richard Schmidt
- */
-public class CsvDataImporter {
-
-    private ArrayList<ArrayList<String>> csvData;
-
-    /**
-     * copied from svgplot
-     * Initiates the parser. The parser reads from the specified {@code reader}
-     * and populates {@link #csvData} with lines of data.
-     *
-     * @param reader
-     *             a reader, like {@link FileReader}, with CSV path
-     * @throws IOException
-     *             if the {@link CSVReader} has problems parsing
-     */
-    public CsvDataImporter(Reader reader) throws IOException {
-        CSVReader csvReader = new CSVReader(reader);
-
-        csvData = new ArrayList<>();
-
-        String[] nextLine;
-        while ((nextLine = csvReader.readNext()) != null) {
-            csvData.add(new ArrayList<String>(Arrays.asList(nextLine)));
-        }
-
-        csvReader.close();
-    }
-
-    // TODO
-    // parse csvData, return a List of points;
-    // svgplot parser may be reused
-}
diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/App.java b/src/main/java/de/tudresden/inf/mci/brailleplot/App.java
index 7c59be79..5890abbf 100644
--- a/src/main/java/de/tudresden/inf/mci/brailleplot/App.java
+++ b/src/main/java/de/tudresden/inf/mci/brailleplot/App.java
@@ -1,7 +1,16 @@
 package de.tudresden.inf.mci.brailleplot;
 
+import parser.CsvOrientation;
+import parser.CsvParser;
+import parser.CsvType;
+import parser.PointListList;
+import parser.Point;
+
+import java.io.FileReader;
+import java.io.IOException;
 import java.util.concurrent.ConcurrentLinkedDeque;
 
+
 /**
  * Main class.
  * Set up the application and run it.
@@ -14,8 +23,18 @@ public final class App {
      * Instantiate application and execute it.
      * @param args Command line parameters.
      */
-    public static void main(final String[] args) {
+    public static void main(final String[] args) throws IOException {
         App app = App.getInstance();
+        String csvPath = "parser_line.csv";
+        CsvType csvType = CsvType.X_ALIGNED;
+        CsvOrientation csvOrientation = CsvOrientation.HORIZONTAL;
+        CsvParser parser = new CsvParser(new FileReader(csvPath), ',', '"');
+        PointListList points = parser.parse(csvType, csvOrientation);
+        for (PointListList.PointList l : points) {
+            for (Point p : l) {
+                System.out.println(p.getX() + p.getY() + p.getName());
+            }
+        }
         System.exit(app.run(args));
     }
 
diff --git a/src/main/java/diagrams/BarChart.java b/src/main/java/diagrams/BarChart.java
new file mode 100644
index 00000000..33ddc3da
--- /dev/null
+++ b/src/main/java/diagrams/BarChart.java
@@ -0,0 +1,12 @@
+package diagrams;
+
+import parser.PointListList;
+
+public class BarChart extends Diagram {
+
+    public BarChart(PointListList p) {
+        this.p = p;
+        p.updateMinMax();
+    }
+
+}
diff --git a/src/main/java/diagrams/Diagram.java b/src/main/java/diagrams/Diagram.java
new file mode 100644
index 00000000..0cc57b27
--- /dev/null
+++ b/src/main/java/diagrams/Diagram.java
@@ -0,0 +1,23 @@
+package diagrams;
+
+import parser.PointListList;
+
+public class Diagram {
+    protected PointListList p;
+
+    public double getMinX() {
+        return p.getMinX();
+    }
+
+    public double getMaxX() {
+        return p.getMaxX();
+    }
+
+    public double getMinY() {
+        return p.getMinY();
+    }
+
+    public double getMaxY() {
+        return p.getMaxY();
+    }
+}
diff --git a/src/main/java/diagrams/LinePlot.java b/src/main/java/diagrams/LinePlot.java
new file mode 100644
index 00000000..b312694f
--- /dev/null
+++ b/src/main/java/diagrams/LinePlot.java
@@ -0,0 +1,11 @@
+package diagrams;
+
+import parser.PointListList;
+
+public class LinePlot extends Diagram {
+
+    public LinePlot(PointListList p) {
+        this.p = p;
+        p.updateMinMax();
+    }
+}
diff --git a/src/main/java/diagrams/ScatterPlot.java b/src/main/java/diagrams/ScatterPlot.java
new file mode 100644
index 00000000..ddce1d1c
--- /dev/null
+++ b/src/main/java/diagrams/ScatterPlot.java
@@ -0,0 +1,11 @@
+package diagrams;
+
+import parser.PointListList;
+
+public class ScatterPlot extends Diagram {
+
+    public ScatterPlot(PointListList p) {
+        this.p = p;
+        p.updateMinMax();
+    }
+}
diff --git a/src/main/java/parser/Axis.java b/src/main/java/parser/Axis.java
new file mode 100644
index 00000000..969cd1d0
--- /dev/null
+++ b/src/main/java/parser/Axis.java
@@ -0,0 +1,151 @@
+package parser;
+
+import java.text.DecimalFormat;
+import java.util.NoSuchElementException;
+
+public abstract class Axis {
+
+	// The following offsets can and shall be overwritten by child classes
+	/** X offset of horizontal axis labels */
+	public final double labelOffsetHorizontalX;
+	/** Y offset of horizontal axis labels */
+	public final double labelOffsetHorizontalY;
+	/** X offset of vertical axis labels */
+	public final double labelOffsetVerticalX;
+	/** Y offset of vertical axis labels */
+	public final double labelOffsetVerticalY;
+
+	protected double ticInterval;
+	protected Range ticRange;
+	protected double gridInterval;
+	protected Range range;
+	protected double labelInterval;
+	protected Range labelRange;
+	protected final DecimalFormat decimalFormat = (DecimalFormat) DecimalFormat.getInstance(Constants.locale);
+	
+	protected String unit;
+	protected String title;
+	
+	/** How much the point position shall be shifted - used for nominal axes.*/
+	protected final double pointOffset;
+
+	/**
+	 * Constructor setting the label and point offsets.
+	 * @param labelOffsetHorizontalX
+	 * @param labelOffsetHorizontalY
+	 * @param labelOffsetVerticalX
+	 * @param labelOffsetVerticalY
+	 * @param pointOffset
+	 */
+	public Axis(double labelOffsetHorizontalX, double labelOffsetHorizontalY, double labelOffsetVerticalX,
+			double labelOffsetVerticalY, double pointOffset, String title, String unit) {
+		this.labelOffsetHorizontalX = labelOffsetHorizontalX;
+		this.labelOffsetHorizontalY = labelOffsetHorizontalY;
+		this.labelOffsetVerticalX = labelOffsetVerticalX;
+		this.labelOffsetVerticalY = labelOffsetVerticalY;
+		this.pointOffset = pointOffset;
+		this.title = title;
+		this.unit = unit;
+	}
+
+	public AxisIterator ticLines() {
+		return new AxisIterator(ticRange, ticInterval);
+	}
+
+	public AxisIterator gridLines() {
+		return new AxisIterator(range, gridInterval);
+	}
+
+	public AxisIterator labelPositions() {
+		return new AxisIterator(labelRange, labelInterval);
+	}
+
+	public abstract String formatForAxisLabel(double value);
+
+	public abstract String formatForAxisAudioLabel(double value);
+	
+	public abstract String formatForSymbolAudioLabel(double value);
+
+	public static class AxisIterator implements java.util.Iterator<Double>, Iterable<Double> {
+
+		private Range range;
+		private double interval;
+		private double current;
+
+		protected AxisIterator(Range range, double interval) {
+			this(range, interval, 0);
+		}
+
+		protected AxisIterator(Range range, double interval, double offset) {
+			this.range = range;
+			this.interval = interval;
+			current = range.getFrom() + offset;
+		}
+
+		/**
+		 * Get the next axis value. There used to be a check for skipping the
+		 * zero value, but now it is not skipped anymore, because there are axis
+		 * configurations where the zero tics and gridlines are needed.
+		 */
+		@Override
+		public boolean hasNext() {
+			return current <= range.getTo();
+		}
+
+		@Override
+		public Double next() {
+			if (!hasNext())
+				throw new NoSuchElementException();
+			double nextCurrent = this.current;
+			this.current += interval;
+			return nextCurrent;
+		}
+
+		@Override
+		public void remove() {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public AxisIterator iterator() {
+			return this;
+		}
+
+	}
+
+	public double getTicInterval() {
+		return ticInterval;
+	}
+
+	public Range getTicRange() {
+		return ticRange;
+	}
+
+	public double getGridInterval() {
+		return gridInterval;
+	}
+
+	public Range getRange() {
+		return range;
+	}
+
+	public double getLabelInterval() {
+		return labelInterval;
+	}
+	
+	public Range getLabelRange() {
+		return labelRange;
+	}
+
+	public String getUnit() {
+		return unit;
+	}
+
+	public String getTitle() {
+		return title;
+	}
+	
+	public double getPointOffset() {
+		return pointOffset;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/parser/CategorialPointListList.java b/src/main/java/parser/CategorialPointListList.java
new file mode 100644
index 00000000..01d428e9
--- /dev/null
+++ b/src/main/java/parser/CategorialPointListList.java
@@ -0,0 +1,69 @@
+package parser;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A {@link PointListList} storing a list of category names. The x values of the
+ * added points should correspond to the index of their category in the category
+ * list.
+ */
+public class CategorialPointListList extends PointListList {
+
+	private static final long serialVersionUID = -1291194891140659342L;
+
+	private List<String> categoryNames;
+	private double maxYSum = Double.NEGATIVE_INFINITY;
+
+	public XType getXType() {
+		return XType.CATEGORIAL;
+	}
+	
+	public CategorialPointListList() {
+		categoryNames = new ArrayList<>();
+	}
+
+	public void addCategory(String name) {
+		categoryNames.add(name);
+	}
+	
+	public String getCategoryName(int index) {
+		try {
+			return categoryNames.get(index);
+		} catch (Exception e) {
+			return "";
+		}
+	}
+	
+	public int getCategoryCount() {
+		return categoryNames.size();
+	}
+	
+	public void setCategoryNames(List<String> categoryNames) {
+		this.categoryNames = categoryNames;
+	}
+
+	public List<String> getCategoryNames() {
+		return categoryNames;
+	}
+	
+	public double getCategorySum(int index) {
+		double sum = 0;
+		for(PointList pointList : this) {
+			if(pointList.size() > index)
+				sum += pointList.get(index).getY();
+		}
+		return sum;
+	}
+
+	@Override
+	public void updateMinMax() {
+		super.updateMinMax();
+		for(int i = 0; i < categoryNames.size(); i++)
+			maxYSum = Math.max(maxYSum, getCategorySum(i));
+	}
+
+	public double getMaxYSum() {
+		return maxYSum;
+	}
+}
diff --git a/src/main/java/parser/Constants.java b/src/main/java/parser/Constants.java
new file mode 100644
index 00000000..2b1ab988
--- /dev/null
+++ b/src/main/java/parser/Constants.java
@@ -0,0 +1,46 @@
+package parser;
+
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.util.*;
+
+public class Constants {
+	public static final String PROPERTIES_FILENAME = "svgplot.properties";
+	public static final Locale locale = new Locale("de");
+	public static final NumberFormat numberFormat = NumberFormat.getInstance(locale);
+	public static final ResourceBundle bundle = ResourceBundle.getBundle("Bundle");
+	public static final double STROKE_WIDTH = 0.5;
+	public static final List<Integer> MARGIN = Collections.unmodifiableList(Arrays.asList(15, 10, 15, 10));
+	/** List of letters for function naming */
+	public static final List<String> FN_LIST = Collections
+			.unmodifiableList(Arrays.asList("f", "g", "h", "i", "j", "k", "l", "m", "o", "p", "q", "r"));
+	/** List of letters for point naming */
+	public static final List<String> PN_LIST = Collections.unmodifiableList(
+			Arrays.asList("A", "B", "C", "D", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "T"));
+	public static final String SPACER_CSS_CLASS = "poi_symbol_bg";
+	public static final DecimalFormat decimalFormat = getSvgDecimalFormat();
+	/** The minimal distance of grid lines in mm */
+	public static final int MIN_GRID_DISTANCE = 10;
+	public static final int MIN_LINE_LENGTH = 30;
+	public static final Point titlePosition = new Point(Constants.MARGIN.get(3), Constants.MARGIN.get(0) + 10);
+	public static final double CHAR_WIDTH = 6.5;
+	public static final double TEXTURE_BORDER_DISTANCE = 2;
+	public static final double TEXTURE_MIN_HEIGHT = 7;
+	public static final double TEXTURE_MIN_WIDTH = 20;
+	public static final double HALF_BAR_DISTANCE = 3;
+	
+	// Used for double comparisons
+	public static final double EPSILON = 1E-10;
+
+	private Constants() {
+	}
+
+	private static final DecimalFormat getSvgDecimalFormat() {
+		DecimalFormat decimalFormat = new DecimalFormat("0.###");
+		DecimalFormatSymbols dfs = new DecimalFormatSymbols();
+		dfs.setDecimalSeparator('.');
+		decimalFormat.setDecimalFormatSymbols(dfs);
+		return decimalFormat;
+	}
+}
diff --git a/src/main/java/parser/CoordinateSystem.java b/src/main/java/parser/CoordinateSystem.java
new file mode 100644
index 00000000..ed98f37a
--- /dev/null
+++ b/src/main/java/parser/CoordinateSystem.java
@@ -0,0 +1,284 @@
+package parser;
+
+import java.util.List;
+
+
+/**
+ * 
+ * @author Gregor Harlan, Jens Bornschein Idea and supervising by Jens
+ *         Bornschein jens.bornschein@tu-dresden.de Copyright by Technische
+ *         Universität Dresden / MCI 2014
+ *
+ */
+public class CoordinateSystem {
+
+	public final Axis xAxis;
+	public final Axis yAxis;
+
+	public final boolean pi;
+
+	/** Origin of the real coordinate system (left upper corner) */
+	private final Point origin;
+
+	/** Size of the drawing area excluding margins */
+	private final Point size;
+
+	/**
+	 * Constructor for a coordinate system with a nominal x axis. TODO replace
+	 * by a factory in order to avoid code duplication
+	 * 
+	 * @param xCategories
+	 * @param yRange
+	 * @param size
+	 * @param diagramContentMargin
+	 */
+	public CoordinateSystem(List<String> xCategories, Range yRange, Point size, List<Integer> diagramContentMargin, String xUnit, String yUnit) {
+		origin = new Point(diagramContentMargin.get(3), diagramContentMargin.get(0));
+
+		this.size = new Point(size);
+		this.size.setX(this.size.getX() - (diagramContentMargin.get(1) + diagramContentMargin.get(3)));
+		this.size.setY(this.size.getY() - (diagramContentMargin.get(0) + diagramContentMargin.get(2)));
+		// this.size.x = Math.min(this.size.x, this.size.y);
+		// this.size.y = this.size.x;
+
+		xAxis = new NominalAxis(xCategories, this.size.getX(), xUnit);
+		yAxis = new MetricAxis(yRange, this.size.getY(), yRange.getName(), yUnit);
+
+		this.pi = false;
+	}
+
+	public CoordinateSystem(Range xRange, Range yRange, Point size, List<Integer> margin, String xUnit, String yUnit) {
+		this(xRange, yRange, size, margin, false, xUnit, yUnit);
+	}
+
+	/**
+	 * Constructor for a coordinate system with metric axes. TODO replace by a
+	 * factory in order to avoid code duplication
+	 * 
+	 * @param xRange
+	 * @param yRange
+	 * @param size
+	 * @param diagramContentMargin
+	 * @param pi
+	 */
+	public CoordinateSystem(Range xRange, Range yRange, Point size, List<Integer> diagramContentMargin, boolean pi, String xUnit, String yUnit) {
+		origin = new Point(diagramContentMargin.get(3), diagramContentMargin.get(0));
+
+		this.size = new Point(size);
+		this.size.setX(this.size.getX() - (diagramContentMargin.get(1) + diagramContentMargin.get(3)));
+		this.size.setY(this.size.getY() - (diagramContentMargin.get(0) + diagramContentMargin.get(2)));
+		// this.size.x = Math.min(this.size.x, this.size.y);
+		// this.size.y = this.size.x;
+
+		xAxis = new MetricAxis(xRange, this.size.getX(), xRange.getName(), xUnit);
+		yAxis = new MetricAxis(yRange, this.size.getY(), yRange.getName(), yUnit);
+
+		this.pi = pi;
+	}
+
+	/**
+	 * Converts a point from virtual to real coordinates.
+	 * 
+	 * @param x
+	 *            | virtual x coordinate
+	 * @param y
+	 *            | virtual y coordinate
+	 * @return real point
+	 */
+	public Point convert(double x, double y) {
+		double newX = origin.getX()
+				+ (x - xAxis.range.getFrom()) * size.getX() / (xAxis.range.getTo() - xAxis.range.getFrom());
+		double newY = origin.getY() + size.getY()
+				- ((y - yAxis.range.getFrom()) * size.getY() / (yAxis.range.getTo() - yAxis.range.getFrom()));
+		return new Point(newX, newY);
+	}
+	
+	/**
+	 * Converts a point from virtual to real coordinates using an offset from the axes.
+	 * 
+	 * @param x
+	 *            | virtual x coordinate
+	 * @param y
+	 *            | virtual y coordinate
+	 * @return real point
+	 */
+	public Point convertWithOffset(double x, double y) {
+		return convert(x + xAxis.getPointOffset(), y + yAxis.getPointOffset());
+	}
+
+	/**
+	 * Converts a point from virtual to real coordinates.
+	 * 
+	 * @param point
+	 *            | virtual coordinates
+	 * @return real point
+	 */
+	public Point convert(Point point) {
+		return convert(point.getX(), point.getY());
+	}
+	
+	/**
+	 * Converts a point from virtual to real coordinates using an offset from the axes.
+	 * 
+	 * @param point
+	 *            | virtual coordinates
+	 * @return real point
+	 */
+	public Point convertWithOffset(Point point) {
+		return convertWithOffset(point.getX(), point.getY());
+	}
+
+	/**
+	 * Converts a point from virtual coordinates and translates it in real
+	 * space.
+	 * 
+	 * @param x
+	 *            | virtual x coordinate
+	 * @param y
+	 *            | virtual y coordinate
+	 * @param dx
+	 *            | real x transformation
+	 * @param dy
+	 *            | real y transformation
+	 * @return real point
+	 */
+	public Point convert(double x, double y, double dx, double dy) {
+		Point real = convert(x, y);
+		real.translate(dx, dy);
+		return real;
+	}
+
+	/**
+	 * Converts a point from virtual coordinates and translates it in real
+	 * space.
+	 * 
+	 * @param point
+	 *            | virtual coordinates
+	 * @param dx
+	 *            | real x transformation
+	 * @param dy
+	 *            | real y transformation
+	 * @return real point
+	 */
+	public Point convert(Point point, double dx, double dy) {
+		return convert(point.getX(), point.getY(), dx, dy);
+	}
+
+	/**
+	 * Converts a distance on the x axis from virtual to real.
+	 * 
+	 * @param distance
+	 *            | virtual distance
+	 * @return real distance
+	 */
+	public double convertXDistance(double distance) {
+		return distance * size.getX() / (xAxis.range.getTo() - xAxis.range.getFrom());
+	}
+
+	/**
+	 * Converts a distance on the y axis from virtual to real.
+	 * 
+	 * @param distance
+	 *            | virtual distance
+	 * @return real distance
+	 */
+	public double convertYDistance(double distance) {
+		return distance * size.getY() / (yAxis.range.getTo() - yAxis.range.getFrom());
+	}
+
+	/**
+	 * Converts two virtual points and calculates their real distance
+	 * 
+	 * @param point1
+	 * @param point2
+	 * @return real distance
+	 */
+	public double convertDistance(Point point1, Point point2) {
+		return convert(point1).distance(convert(point2));
+	}
+
+	/**
+	 * Formats the x value of a point with respect to if Pi is set in the
+	 * coordinate system.
+	 * 
+	 * @param x
+	 *            x-value
+	 * @return formated string for the point
+	 */
+	public String formatX(double x) {
+		String str = xAxis.formatForAxisLabel(x);
+		if (pi && !"0".equals(str)) {
+			str += " pi";
+		}
+		return str;
+	}
+
+	/**
+	 * Formats the x value of a point with respect to if Pi is set in the
+	 * coordinate system, for axis audio labels.
+	 * 
+	 * @param x
+	 *            x-value
+	 * @return formated string for the point
+	 */
+	public String formatXForAxisSpeech(double x) {
+		String str = xAxis.formatForAxisAudioLabel(x);
+		if (pi && !"0".equals(str)) {
+			str += " pi";
+		}
+		return str;
+	}
+	
+	/**
+	 * Formats the x value of a point with respect to if Pi is set in the
+	 * coordinate system, for symbol audio labels.
+	 * 
+	 * @param x
+	 *            x-value
+	 * @return formated string for the point
+	 */
+	public String formatXForSymbolSpeech(double x) {
+		String str = xAxis.formatForSymbolAudioLabel(x);
+		if (pi && !"0".equals(str)) {
+			str += " pi";
+		}
+		return str;
+	}
+
+	/**
+	 * Formats the y value of a point.
+	 * 
+	 * @param y
+	 *            y-value
+	 * @return formated string for the point
+	 */
+	public String formatY(double y) {
+		return yAxis.formatForAxisLabel(y);
+	}
+
+	/**
+	 * Formats a Point that it is optimized for speech output. E.g. (x / y)
+	 * 
+	 * @param point
+	 *            The point that should be transformed into a textual
+	 *            representation
+	 * @return formated string for the point with '/' as delimiter
+	 */
+	public String formatForSpeech(Point point) {
+		return ((point.getName() != null && !point.getName().isEmpty()) ? point.getName() + " " : "")
+				+ formatXForSymbolSpeech(point.getX()) + " / " + formatY(point.getY());
+	}
+	
+	/**
+	 * Formats a Point that it is optimized for speech output for an axis audio label.
+	 * 
+	 * @param point
+	 *            The point that should be transformed into a textual
+	 *            representation
+	 * @return formated string for the point with '/' as delimiter
+	 */
+	public String formatForAxisSpeech(Point point) {
+		return ((point.getName() != null && !point.getName().isEmpty()) ? point.getName() + " " : "")
+				+ formatXForAxisSpeech(point.getX()) + " / " + formatY(point.getY());
+	}
+}
diff --git a/src/main/java/parser/CsvDotParser.java b/src/main/java/parser/CsvDotParser.java
new file mode 100644
index 00000000..5294a3c8
--- /dev/null
+++ b/src/main/java/parser/CsvDotParser.java
@@ -0,0 +1,130 @@
+package parser;
+
+import parser.PointListList.PointList;
+
+import java.text.ParseException;
+import java.util.Iterator;
+import java.util.List;
+
+public class CsvDotParser extends CsvParseAlgorithm {
+
+	/**
+	 * Parses scattered point data in horizontal data sets, alternating x and y. The
+	 * first column contains the row name in the x row.
+	 * 
+	 * @return the parsed data
+	 */
+	public PointListList parseAsHorizontalDataSets(List<? extends List<String>> csvData) {
+		int row = 0;
+
+		PointListList pointListList = new PointListList();
+
+		// Continue as long as there are at least two further rows left
+		while (csvData.size() >= row + 2) {
+			PointList rowPoints = new PointList();
+
+			Iterator<String> xRowIterator = csvData.get(row).iterator();
+			Iterator<String> yRowIterator = csvData.get(row + 1).iterator();
+
+			row += 2;
+
+			// Get the row name
+			if (xRowIterator.hasNext() && yRowIterator.hasNext()) {
+				rowPoints.setName(xRowIterator.next());
+				yRowIterator.next();
+			} else {
+				continue;
+			}
+
+			// Get the row values
+			while (xRowIterator.hasNext() && yRowIterator.hasNext()) {
+				Number xValue;
+				Number yValue;
+				try {
+					xValue = Constants.numberFormat.parse(xRowIterator.next());
+					yValue = Constants.numberFormat.parse(yRowIterator.next());
+				} catch (ParseException e) {
+					continue;
+				}
+				Point newPoint = new Point(xValue.doubleValue(), yValue.doubleValue());
+				rowPoints.insertSorted(newPoint);
+			}
+
+			// If there were no points found, do not add the row to the list
+			if (!rowPoints.isEmpty())
+				pointListList.add(rowPoints);
+		}
+
+		return pointListList;
+	}
+
+	/**
+	 * Parses scattered point data in vertical data sets, alternating x and y. The
+	 * first row contains the column name in the x column.
+	 * 
+	 * @return the parsed data
+	 */
+	@Override
+	public PointListList parseAsVerticalDataSets(List<? extends List<String>> csvData) {
+		int row = 0;
+
+		PointListList pointListList = new PointListList();
+
+		if (csvData.isEmpty())
+			return pointListList;
+
+		// Iterate over the first row in order to get the headers
+		int col = 0;
+		for (String header : csvData.get(0)) {
+			if (col % 2 == 0) {
+				PointList pointList = new PointList();
+				pointList.setName(header);
+				pointListList.add(pointList);
+			}
+			col++;
+		}
+
+		row++;
+
+		// Continue as long as there is at least one further rows left
+		while (csvData.size() >= row + 1) {
+			List<String> fields = csvData.get(row);
+			Iterator<String> fieldIterator = fields.iterator();
+
+			col = -1;
+
+			while (fieldIterator.hasNext()) {
+				String xRaw = fieldIterator.next();
+				String yRaw;
+
+				col++;
+
+				if (!fieldIterator.hasNext())
+					break;
+				
+				yRaw = fieldIterator.next();
+
+				Number xValue;
+				Number yValue;
+
+				try {
+					xValue = Constants.numberFormat.parse(xRaw);
+					yValue = Constants.numberFormat.parse(yRaw);
+				} catch (ParseException e) {
+					col++;
+					continue;
+				}
+
+				Point point = new Point(xValue.doubleValue(), yValue.doubleValue());
+
+				addPointToPointListList(pointListList, col / 2, point);
+
+				col++;
+			}
+
+			row++;
+		}
+
+		return pointListList;
+	}
+}
diff --git a/src/main/java/parser/CsvOrientation.java b/src/main/java/parser/CsvOrientation.java
new file mode 100644
index 00000000..45bc2dcd
--- /dev/null
+++ b/src/main/java/parser/CsvOrientation.java
@@ -0,0 +1,34 @@
+package parser;
+
+import com.beust.jcommander.IStringConverter;
+
+public enum CsvOrientation {
+	
+	HORIZONTAL, VERTICAL;
+	
+    public static CsvOrientation fromString(String code) {
+        if(code.equals("vertical") || code.equals("v"))
+        	return CsvOrientation.VERTICAL;
+        else
+        	return CsvOrientation.HORIZONTAL;
+    }
+
+	@Override
+	public String toString() {
+		return super.toString().toLowerCase();
+	}
+	
+	public static class CsvOrientationConverter implements IStringConverter<CsvOrientation> {
+
+		public CsvOrientationConverter() {
+			super();
+		}
+		
+		@Override
+		public CsvOrientation convert(String value) {
+			CsvOrientation convertedValue = CsvOrientation.fromString(value);
+			return convertedValue;
+		}
+		
+	}
+}
diff --git a/src/main/java/parser/CsvParseAlgorithm.java b/src/main/java/parser/CsvParseAlgorithm.java
new file mode 100644
index 00000000..878738e7
--- /dev/null
+++ b/src/main/java/parser/CsvParseAlgorithm.java
@@ -0,0 +1,49 @@
+package parser;
+
+import parser.PointListList.PointList;
+
+import java.util.List;
+
+/**
+ * An algorithm for parsing CSV data. Contains implementations for two
+ * orientations of the data in the file.
+ */
+public abstract class CsvParseAlgorithm {
+	/**
+	 * If the data sets are oriented horizontally, i.e. in rows, parse the rows
+	 * into {@link PointList PointLists}.
+	 * 
+	 * @param csvData
+	 * @return
+	 */
+	public abstract PointListList parseAsHorizontalDataSets(List<? extends List<String>> csvData);
+
+	/**
+	 * If the data sets are oriented vertically, i.e. in columns, parse the
+	 * columns into {@link PointList PointLists}.
+	 * 
+	 * @param csvData
+	 * @return
+	 */
+	public abstract PointListList parseAsVerticalDataSets(List<? extends List<String>> csvData);
+
+	/**
+	 * Adds a {@code point} to a {@link PointList} in a {@link PointListList},
+	 * specified by {@code listIndex}. Adds more {@link PointList PointLists} if
+	 * needed.
+	 * 
+	 * @param pointListList
+	 *            the {@link PointListList} to which the point shall be added
+	 * @param listIndex
+	 *            the index of the list to which the point shall be added
+	 * @param point
+	 *            the point which shall be added
+	 */
+	protected void addPointToPointListList(PointListList pointListList, int listIndex, Point point) {
+		while (pointListList.size() < listIndex) {
+			pointListList.add(new PointList());
+		}
+
+		pointListList.get(listIndex).insertSorted(point);
+	}
+}
diff --git a/src/main/java/parser/CsvParser.java b/src/main/java/parser/CsvParser.java
new file mode 100644
index 00000000..8cf432b1
--- /dev/null
+++ b/src/main/java/parser/CsvParser.java
@@ -0,0 +1,71 @@
+package parser;
+
+import com.opencsv.CSVReader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public class CsvParser {
+
+	static final Logger log = LoggerFactory.getLogger(CsvParser.class);
+	
+	private ArrayList<ArrayList<String>> csvData;
+
+	/**
+	 * Initiates the parser. The parser reads from the specified {@code reader}
+	 * and populates {@link #csvData}.
+	 * 
+	 * @param reader
+	 *            a reader, like {@link FileReader}
+	 * @param separator
+	 * @param quoteChar
+	 * @throws IOException
+	 *             if the {@link CSVReader} has problems parsing
+	 */
+	public CsvParser(Reader reader, char separator, char quoteChar) throws IOException {
+		CSVReader csvReader = new CSVReader(reader, separator, quoteChar);
+
+		csvData = new ArrayList<>();
+
+		String[] nextLine;
+		while ((nextLine = csvReader.readNext()) != null) {
+			csvData.add(new ArrayList<String>(Arrays.asList(nextLine)));
+		}
+
+		csvReader.close();
+	}
+	
+	public PointListList parse(CsvType csvType, CsvOrientation csvOrientation) {
+		CsvParseAlgorithm csvParseAlgorithm;
+		
+		log.info("Parse die Daten als \"{}\", Orientierung \"{}\"", csvType, csvOrientation);
+		
+		switch (csvType) {
+		case DOTS:
+			csvParseAlgorithm = new CsvDotParser();
+			break;
+		case X_ALIGNED:
+			csvParseAlgorithm = new CsvXAlignedParser();
+			break;
+		case X_ALIGNED_CATEGORIES:
+			csvParseAlgorithm = new CsvXAlignedCategoriesParser();
+			break;
+		default:
+			return null;
+		}
+		
+		switch (csvOrientation) {
+		case HORIZONTAL:
+			return csvParseAlgorithm.parseAsHorizontalDataSets(csvData);
+		case VERTICAL:
+			return csvParseAlgorithm.parseAsVerticalDataSets(csvData);
+		default:
+			return null;
+		}
+	}
+}
diff --git a/src/main/java/parser/CsvType.java b/src/main/java/parser/CsvType.java
new file mode 100644
index 00000000..6288a67f
--- /dev/null
+++ b/src/main/java/parser/CsvType.java
@@ -0,0 +1,52 @@
+package parser;
+
+import com.beust.jcommander.IStringConverter;
+
+/**
+ * Determines what data is represented how by the CSV file. The values are
+ * structural properties, whereas the {@link XType} held by every value
+ * determines whether the x values are metric or categorial.
+ */
+public enum CsvType {
+	DOTS(XType.METRIC), X_ALIGNED(XType.METRIC), X_ALIGNED_CATEGORIES(XType.CATEGORIAL);
+
+	public final XType xType;
+
+	private CsvType(XType xType) {
+		this.xType = xType;
+	}
+
+	public static CsvType fromString(String value) {
+		switch (value.toLowerCase()) {
+		case "x_aligned":
+		case "xa":
+			return CsvType.X_ALIGNED;
+		case "x_aligned_categories":
+		case "xac":
+			return CsvType.X_ALIGNED_CATEGORIES;
+		case "dots":
+		case "d":
+		default:
+			return DOTS;
+		}
+	}
+
+	@Override
+	public String toString() {
+		return super.toString().toLowerCase();
+	}
+
+	public static class CsvTypeConverter implements IStringConverter<CsvType> {
+
+		public CsvTypeConverter() {
+			super();
+		}
+
+		@Override
+		public CsvType convert(String value) {
+			CsvType convertedValue = CsvType.fromString(value);
+			return convertedValue;
+		}
+
+	}
+}
diff --git a/src/main/java/parser/CsvXAlignedCategoriesParser.java b/src/main/java/parser/CsvXAlignedCategoriesParser.java
new file mode 100644
index 00000000..8429acc3
--- /dev/null
+++ b/src/main/java/parser/CsvXAlignedCategoriesParser.java
@@ -0,0 +1,134 @@
+package parser;
+
+import parser.PointListList.PointList;
+
+import java.text.ParseException;
+import java.util.Iterator;
+import java.util.List;
+
+
+public class CsvXAlignedCategoriesParser extends CsvParseAlgorithm {
+
+	@Override
+	public PointListList parseAsHorizontalDataSets(List<? extends List<String>> csvData) {
+		CategorialPointListList pointListList = new CategorialPointListList();
+
+		Iterator<? extends List<String>> rowIterator = csvData.iterator();
+		
+		if(!rowIterator.hasNext())
+			return pointListList;
+		
+		Iterator<String> lineIterator = rowIterator.next().iterator();
+		
+		// Move the iterator to the first category name
+		if(!lineIterator.hasNext())
+			return pointListList;
+		lineIterator.next();
+		if(!lineIterator.hasNext())
+			return pointListList;
+		
+		// Store all categories
+		while(lineIterator.hasNext()) {
+			pointListList.addCategory(lineIterator.next());
+		}
+		
+		// Store each row's data set
+		while(rowIterator.hasNext()) {
+			lineIterator = rowIterator.next().iterator();
+			
+			// Create a PointList with the title of the data set
+			if(!lineIterator.hasNext())
+				continue;
+			PointList pointList = new PointList();
+			pointList.setName(lineIterator.next());
+			pointListList.add(pointList);
+			
+			// Add all the points
+			int colPosition = 0;
+			while (lineIterator.hasNext()) {
+				if(colPosition >= pointListList.getCategoryCount())
+					break;
+				
+				// Find out the y value
+				Number yValue;
+				try {
+					yValue = Constants.numberFormat.parse(lineIterator.next());
+				} catch (ParseException e) {
+					colPosition++;
+					continue;
+				}
+				
+				// Add the new point
+				Point newPoint = new Point(colPosition, yValue.doubleValue());
+				pointList.insertSorted(newPoint);
+				colPosition++;
+			}
+		}
+		
+		return pointListList;
+	}
+
+	@Override
+	public PointListList parseAsVerticalDataSets(List<? extends List<String>> csvData) {
+		CategorialPointListList pointListList = new CategorialPointListList();
+		Iterator<? extends List<String>> rowIterator = csvData.iterator();
+
+		
+		if(!rowIterator.hasNext())
+			return pointListList;
+
+		Iterator<String> lineIterator = rowIterator.next().iterator();
+
+		// Move the iterator to the first title
+		if(!lineIterator.hasNext())
+			return pointListList;
+
+		lineIterator.next();
+
+		if(!lineIterator.hasNext())
+		{System.out.print("1");
+			return pointListList;}
+
+		// Add a PointList for each title
+		while(lineIterator.hasNext()) {
+			PointList pointList = new PointList();
+			pointList.setName(lineIterator.next());
+			pointListList.add(pointList);
+		}
+
+		// Add the data
+		int categoryCounter = 0;
+		while(rowIterator.hasNext()) {
+			lineIterator = rowIterator.next().iterator();
+			if(!lineIterator.hasNext()) {
+				categoryCounter++;
+				continue;
+			}
+			
+			// Find out the category title
+			String currentCategory = lineIterator.next();
+			pointListList.addCategory(currentCategory);
+			
+			// Find out the y values and add the points to the respective lists
+			int currentDataSet = 0;
+			while(lineIterator.hasNext()) {
+				Number yValue;
+				try {
+					yValue = Constants.numberFormat.parse(lineIterator.next());
+				} catch (ParseException e) {
+					currentDataSet++;
+					continue;
+				}
+				
+				Point newPoint = new Point(categoryCounter, yValue.doubleValue());
+				addPointToPointListList(pointListList, currentDataSet, newPoint);
+				currentDataSet++;
+			}
+			
+			categoryCounter++;
+		}
+
+		return pointListList;		
+	}
+
+}
diff --git a/src/main/java/parser/CsvXAlignedParser.java b/src/main/java/parser/CsvXAlignedParser.java
new file mode 100644
index 00000000..7ac6c46d
--- /dev/null
+++ b/src/main/java/parser/CsvXAlignedParser.java
@@ -0,0 +1,144 @@
+package parser;
+
+import parser.PointListList.PointList;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+
+public class CsvXAlignedParser extends CsvParseAlgorithm {
+
+	@Override
+	public PointListList parseAsHorizontalDataSets(List<? extends List<String>> csvData) {
+		PointListList pointListList = new PointListList();
+		List<Number> xValues = new ArrayList<>();
+		Iterator<? extends List<String>> rowIterator = csvData.iterator();
+		
+		if(!rowIterator.hasNext())
+			return pointListList;
+		
+		Iterator<String> lineIterator = rowIterator.next().iterator();
+		
+		// Move the iterator to the x value
+		if(!lineIterator.hasNext())
+			return pointListList;
+		lineIterator.next();
+		if(!lineIterator.hasNext())
+		{System.out.print("1");
+			return pointListList;}
+		
+		// Store all x values, if one is not specified store NaN
+		while(lineIterator.hasNext()) {
+			Number xValue;
+			try {
+				xValue = Constants.numberFormat.parse(lineIterator.next());
+			} catch (ParseException e) {
+				xValue = Double.NaN;
+			}
+			xValues.add(xValue);
+		}
+		
+		// Store each row's data set
+		while(rowIterator.hasNext()) {
+			lineIterator = rowIterator.next().iterator();
+			
+			// Create a PointList with the title of the data set
+			if(!lineIterator.hasNext())
+				continue;
+			PointList pointList = new PointList();
+			pointList.setName(lineIterator.next());
+			pointListList.add(pointList);
+			
+			// Add all the points
+			int colPosition = 0;
+			while (lineIterator.hasNext()) {
+				if(colPosition >= xValues.size())
+					break;
+				Number xValue = xValues.get(colPosition);
+				if(xValue.equals(Double.NaN)) {
+					lineIterator.next();
+					colPosition++;
+					continue;
+				}
+				
+				// Find out the y value
+				Number yValue;
+				try {
+					yValue = Constants.numberFormat.parse(lineIterator.next());
+				} catch (ParseException e) {
+					colPosition++;
+					continue;
+				}
+				
+				// Add the new point
+				Point newPoint = new Point(xValue.doubleValue(), yValue.doubleValue());
+				pointList.insertSorted(newPoint);
+				colPosition++;
+			}
+		}
+		
+		return pointListList;
+	}
+
+	@Override
+	public PointListList parseAsVerticalDataSets(List<? extends List<String>> csvData) {
+		PointListList pointListList = new PointListList();
+		Iterator<? extends List<String>> rowIterator = csvData.iterator();
+		
+		if(!rowIterator.hasNext())
+			return pointListList;
+		
+		Iterator<String> lineIterator = rowIterator.next().iterator();
+		
+		// Move the iterator to the first title
+		if(!lineIterator.hasNext())
+			return pointListList;
+		lineIterator.next();
+		if(!lineIterator.hasNext())
+			return pointListList;
+		
+		// Add a PointList for each title
+		while(lineIterator.hasNext()) {
+			PointList pointList = new PointList();
+			pointList.setName(lineIterator.next());
+			pointListList.add(pointList);
+		}
+		
+		// Add the data
+		while(rowIterator.hasNext()) {
+			lineIterator = rowIterator.next().iterator();
+			if(!lineIterator.hasNext())
+				continue;
+			
+			// Find out the x value
+			Number xValue;
+			try {
+				xValue = Constants.numberFormat.parse(lineIterator.next());
+			} catch (ParseException e) {
+				continue;
+			}
+			
+			// Find out the y values and add the points to the respective lists
+			int currentDataSet = 0;
+			while(lineIterator.hasNext()) {
+				Number yValue;
+				try {
+					yValue = Constants.numberFormat.parse(lineIterator.next());
+				} catch (ParseException e) {
+					currentDataSet++;
+					continue;
+				}
+				
+				Point newPoint = new Point(xValue.doubleValue(), yValue.doubleValue());
+				addPointToPointListList(pointListList, currentDataSet, newPoint);
+				currentDataSet++;
+			}
+			
+		}
+		
+		return pointListList;		
+	}
+
+}
diff --git a/src/main/java/parser/MetricAxis.java b/src/main/java/parser/MetricAxis.java
new file mode 100644
index 00000000..f806a3d1
--- /dev/null
+++ b/src/main/java/parser/MetricAxis.java
@@ -0,0 +1,132 @@
+package parser;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 
+ * @author Gregor Harlan, Jens Bornschein Idea and supervising by Jens
+ *         Bornschein jens.bornschein@tu-dresden.de Copyright by Technische
+ *         Universität Dresden / MCI 2014
+ *
+ */
+public class MetricAxis extends Axis {
+	public final double atom;
+	public final int atomCount;
+	public final List<Double> intervalSteps;
+
+	public MetricAxis(Range axisRange, double size, String title, String unit) {
+		
+		// Set the label offsets
+		super(-5, 20, -10, 5, 0, title, unit);
+		
+		boolean finished = false;
+		double interval = 0;
+		range = new Range(0, 0);
+		range.setName(axisRange.getName());
+		int dimensionExp;
+		double dimension;
+		double factor;
+		do {
+			/*
+			 * Calculate how many tics there can maximally be without violating
+			 * the minimal distance of grid lines constraint.
+			 */
+			int maxTics = (int) (size / Constants.MIN_GRID_DISTANCE);
+			// Calculate which interval (virtual) the tics must minimally have.
+			interval = axisRange.distance() / maxTics;
+			dimensionExp = 0;
+			int direction = interval < 1 ? -1 : 1;
+			while (direction * 0.5 * Math.pow(10, dimensionExp) < direction * interval) {
+				dimensionExp += direction;
+			}
+			if (direction == 1) {
+				dimensionExp--;
+			}
+			dimension = Math.pow(10, dimensionExp);
+			factor = getFactorForIntervalAndDimension(interval, dimension);
+			finished = true;
+			interval = factor * dimension * 2;
+			range.setFrom(((int) (axisRange.getFrom() / interval)) * interval);
+			range.setTo(((int) (axisRange.getTo() / interval)) * interval);
+			if (range.getFrom() > axisRange.getFrom()) {
+				axisRange.setFrom(range.getFrom() - interval);
+				finished = false;
+			}
+			if (range.getTo() < axisRange.getTo()) {
+				axisRange.setTo(range.getTo() + interval);
+				finished = false;
+			}
+		} while (!finished);
+
+		gridInterval = interval;
+
+		ticInterval = interval; // TODO set this to 2 * interval if needed, maybe create an option
+		ticRange = new Range(Math.ceil(range.getFrom() / ticInterval) * ticInterval,
+				Math.floor(range.getTo() / ticInterval) * ticInterval);
+		
+		labelRange = ticRange;
+		labelInterval = ticInterval * 2;
+
+		decimalFormat.setMaximumFractionDigits(Math.max(0, -dimensionExp + 2));
+
+		atom = dimension / 100;
+		atomCount = (int) (range.distance() / atom + 1);
+
+		intervalSteps = new ArrayList<>();
+		calculateIntervalSteps(dimension, factor);
+	}
+
+	@Override
+	public String formatForAxisLabel(double value) {
+		String str = decimalFormat.format(value);
+		return "-0".equals(str) ? "0" : str;
+	}
+	
+	@Override
+	public String formatForAxisAudioLabel(double value) {
+		return formatForAxisLabel(value);
+	}
+	
+	@Override
+	public String formatForSymbolAudioLabel(double value) {
+		return formatForAxisLabel(value);
+	}
+	
+	/**
+	 * @param dimension
+	 * @param factor
+	 */
+	private void calculateIntervalSteps(double dimension, double factor) {
+		int i = 0;
+		if (Math.abs(factor - 2.5) < Constants.EPSILON) {
+			intervalSteps.add(i++, 2.5 * dimension);
+			intervalSteps.add(i++, dimension);
+		} else if (Math.abs(factor - 1) < Constants.EPSILON) {
+			intervalSteps.add(i++, dimension);
+		}
+
+		intervalSteps.add(i++, 0.5 * dimension);
+		intervalSteps.add(i++, 0.1 * dimension);
+		intervalSteps.add(i++, 0.05 * dimension);
+		intervalSteps.add(i, 0.01 * dimension);
+	}
+
+	/**
+	 * @param interval
+	 * @param dimension
+	 * @return the calculated factor
+	 */
+	private double getFactorForIntervalAndDimension(double interval, double dimension) {
+		double factor;
+		if (interval > dimension) {
+			factor = 2.5;
+		} else if (interval > 0.5 * dimension) {
+			factor = 1;
+		} else {
+			factor = 0.5;
+		}
+		return factor;
+	}
+
+}
diff --git a/src/main/java/parser/NominalAxis.java b/src/main/java/parser/NominalAxis.java
new file mode 100644
index 00000000..2762d5f3
--- /dev/null
+++ b/src/main/java/parser/NominalAxis.java
@@ -0,0 +1,88 @@
+package parser;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Axis for displaying nominals.
+ */
+public class NominalAxis extends Axis {
+
+	static final Logger log = LoggerFactory.getLogger(NominalAxis.class);
+
+	/**
+	 * The categories displayed on the Axis in order.
+	 */
+	protected List<String> categories;
+
+	/**
+	 * The nominal axis gets constructed so that each tic corresponds to one
+	 * category. The tics are however shown
+	 * 
+	 * @param categories
+	 * @param size
+	 * @param unit
+	 */
+	public NominalAxis(List<String> categories, double size, String unit) {
+		// TODO: upon implementation of vertical nominal axes set the values
+		// correctly
+		super(Constants.CHAR_WIDTH, 15, -10, -Constants.CHAR_WIDTH, 0.5, null, unit);
+
+		this.categories = categories;
+
+		double categorySize = size / categories.size();
+		int maxLabelLength = 0;
+		for (String label : categories)
+			if (label.length() > maxLabelLength)
+				maxLabelLength = label.length();
+		if (categorySize < Constants.CHAR_WIDTH * (maxLabelLength + 1)) {
+			log.warn(
+					"Der Platz reicht nicht aus, um Achsenbeschriftungen darzustellen. Die längste Beschriftung hat eine Länge von "
+							+ maxLabelLength + " Zeichen.");
+		}
+
+		// Subdivide the axis into sections for each category
+		ticInterval = 1;
+		gridInterval = 1;
+		labelInterval = 1;
+
+		ticRange = new Range(0, categories.size());
+		range = ticRange;
+		labelRange = new Range(0, categories.size() - 1);
+
+	}
+
+	@Override
+	public String formatForAxisLabel(double value) {
+		int categoryNumber = (int) Math.round(value);
+		if (categories.size() <= categoryNumber || categoryNumber < 0)
+			return null;
+		// throw new IllegalArgumentException("The selected category does not
+		// exist");
+		return categories.get(categoryNumber);
+	}
+
+	@Override
+	public String formatForAxisAudioLabel(double value) {
+		int categoryNumber = (int) Math.round(value);
+
+		if (categoryNumber == 0) {
+			return "|" + categories.get(categoryNumber);
+		} else if (categoryNumber == categories.size()) {
+			return categories.get(categoryNumber - 1) + "|";
+		} else if (categoryNumber > 0 && categoryNumber < categories.size()) {
+			return categories.get(categoryNumber - 1) + "|" + categories.get(categoryNumber);
+		} else {
+			return null;
+		}
+	}
+
+	@Override
+	public String formatForSymbolAudioLabel(double value) {
+		return formatForAxisLabel(value);
+	}
+
+}
diff --git a/src/main/java/parser/Point.java b/src/main/java/parser/Point.java
new file mode 100644
index 00000000..8add0af1
--- /dev/null
+++ b/src/main/java/parser/Point.java
@@ -0,0 +1,242 @@
+package parser;
+
+import org.w3c.dom.Element;
+
+import com.beust.jcommander.IStringConverter;
+
+
+/**
+ * A point in a coordinate system specified by an x and y coordinate. Can also
+ * have a name and an SVG symbol. Provides helper methods, e.g. for calculating
+ * the distance between two points.
+ * 
+ * @author Gregor Harlan Idea and supervising by Jens Bornschein
+ *         jens.bornschein@tu-dresden.de Copyright by Technische Universität
+ *         Dresden / MCI 2014
+ *
+ */
+public class Point implements Comparable<Point> {
+
+	protected double x;
+	protected double y;
+	protected String name;
+	protected Element symbol;
+
+	/**
+	 * Copy constructor
+	 * 
+	 * @param otherPoint
+	 *            the point to copy
+	 */
+	public Point(Point otherPoint) {
+		this(otherPoint.getX(), otherPoint.getY(), otherPoint.getName(),
+				 otherPoint.getSymbol() != null ? (Element) otherPoint.getSymbol().cloneNode(true) : null);
+	}
+
+	/**
+	 * Represents a two dimensional Point in the plot
+	 * 
+	 * @param x
+	 *            | x (horizontal) position of the point
+	 * @param y
+	 *            | y (vertical) position of the point
+	 */
+	public Point(double x, double y) {
+		this(x, y, "", null);
+	}
+
+	/**
+	 * Represents a two dimensional Point in the plot
+	 * 
+	 * @param x
+	 *            | x (horizontal) position of the point
+	 * @param y
+	 *            | y (vertical) position of the point
+	 * @param name
+	 *            | the name of the point
+	 */
+	public Point(double x, double y, String name) {
+		this(x, y, name, null);
+	}
+
+	/**
+	 * Represents a two dimensional Point in the plot
+	 * 
+	 * @param x
+	 *            | x (horizontal) position of the point
+	 * @param y
+	 *            | y (vertical) position of the point
+	 * @param symbol
+	 *            | the symbol to use for the point
+	 */
+	public Point(double x, double y, Element symbol) {
+		this(x, y, "", symbol);
+	}
+
+	/**
+	 * Represents a two dimensional Point in the plot
+	 * 
+	 * @param x
+	 *            | x (horizontal) position of the point
+	 * @param y
+	 *            | y (vertical) position of the point
+	 * @param name
+	 *            | the name of the point
+	 * @param symbol
+	 *            | the symbol to use for the point
+	 */
+	public Point(double x, double y, String name, Element symbol) {
+		this.setX(x);
+		this.setY(y);
+		this.setName(name);
+		this.setSymbol(symbol);
+	}
+
+	/**
+	 * Move the point
+	 * 
+	 * @param dx
+	 *            | movement in x (horizontal) direction
+	 * @param dy
+	 *            | movement in y (vertical) direction
+	 */
+	public void translate(double dx, double dy) {
+		setX(getX() + dx);
+		setY(getY() + dy);
+	}
+
+	/**
+	 * formats the x value as an svg compatible decimal value.
+	 * 
+	 * @return
+	 */
+	public String x() {
+		return SvgTools.format2svg(getX());
+	}
+
+	/**
+	 * formats the y value as an svg compatible decimal value.
+	 * 
+	 * @return
+	 */
+	public String y() {
+		return SvgTools.format2svg(getY());
+	}
+
+	@Override
+	/**
+	 * formats the x and y values as svg compatible decimal values and combine
+	 * them by a comma.
+	 * 
+	 * @return x,y
+	 */
+	public String toString() {
+		return x() + "," + y();
+	}
+
+	/**
+	 * computes the two dimensional euclidean distance of two points.
+	 * 
+	 * @param other
+	 *            | second point
+	 * @return the two dimensional euclidean distance between this and the other
+	 *         point.
+	 */
+	public double distance(Point other) {
+		return Math.sqrt(Math.pow(other.getX() - getX(), 2) + Math.pow(other.getY() - getY(), 2));
+	}
+
+	public static class Converter implements IStringConverter<Point> {
+		/**
+		 * Convert a formatted string to a point. The format is:
+		 * {@code [<x>][,<y>]} Omitted values will default to 0.
+		 * 
+		 * @param value
+		 *            | formatted string
+		 */
+		@Override
+		public Point convert(String value) {
+			String[] s = value.split(",");
+			return new Point(s.length > 0 ? Double.parseDouble(s[0]) : 0, s.length > 1 ? Double.parseDouble(s[1]) : 0);
+		}
+	}
+
+	/**
+	 * Compares with x priority. Returns -1 if p2 is null.
+	 * 
+	 * @param p2
+	 *            | other point
+	 * @return
+	 */
+	@Override
+	public int compareTo(Point p2) {
+		if (p2 != null) {
+			if (Math.abs(p2.getX() - getX()) < Constants.EPSILON) {
+				return getY() < p2.getY() ? -1 : 1;
+			} else
+				return getX() < p2.getX() ? -1 : 1;
+		}
+		return -1;
+	}
+
+	/**
+	 * Compare the y values of two points. Returns -1 if p2 is null.
+	 * 
+	 * @param p2
+	 *            | other point
+	 * @return
+	 */
+	public int compareToY(Point p2) {
+		if (p2 != null) {
+			return getY() < p2.getY() ? -1 : 1;
+		}
+		return -1;
+	}
+
+	/**
+	 * Compare the x values of two points. Returns -1 if p2 is null.
+	 * 
+	 * @param p2
+	 *            | other point
+	 * @return
+	 */
+	public int compareToX(Point p2) {
+		if (p2 != null) {
+			return getX() < p2.getX() ? -1 : 1;
+		}
+		return -1;
+	}
+
+	public double getX() {
+		return x;
+	}
+
+	public void setX(double x) {
+		this.x = x;
+	}
+
+	public double getY() {
+		return y;
+	}
+
+	public void setY(double y) {
+		this.y = y;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Element getSymbol() {
+		return symbol;
+	}
+
+	public void setSymbol(Element symbol) {
+		this.symbol = symbol;
+	}
+
+}
diff --git a/src/main/java/parser/PointListList.java b/src/main/java/parser/PointListList.java
new file mode 100644
index 00000000..aed9db9f
--- /dev/null
+++ b/src/main/java/parser/PointListList.java
@@ -0,0 +1,245 @@
+package parser;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import com.beust.jcommander.IStringConverter;
+
+/**
+ * 
+ * @author Gregor Harlan, Jens Bornschein Idea and supervising by Jens
+ *         Bornschein jens.bornschein@tu-dresden.de Copyright by Technische
+ *         Universität Dresden / MCI 2014
+ *
+ */
+public class PointListList extends ArrayList<PointListList.PointList> {
+
+	private static final long serialVersionUID = 6902232865786868851L;
+	protected Double maxX = Double.NEGATIVE_INFINITY;
+	protected Double maxY = Double.NEGATIVE_INFINITY;
+	protected Double minX = Double.POSITIVE_INFINITY;
+	protected Double minY = Double.POSITIVE_INFINITY;
+	
+	public XType getXType() {
+		return XType.METRIC;
+	}
+
+	public PointListList() {
+		this("");
+	}
+
+	public PointListList(String pointLists) {
+		
+		if (pointLists == null || pointLists.isEmpty())
+			return;
+
+		// TODO: load from file
+
+		// pointLists = pointLists.replaceAll("[^\\d.,^\\s+,^\\{^\\}^-]", "");
+		String[] lists = pointLists.split("\\}");
+		for (String l : lists) {
+			PointList pl = new PointList(l);
+			if (!pl.isEmpty()) {
+				this.add(pl);
+			}
+		}
+	}
+	
+	@Override
+	public boolean add(PointList pl) {
+		boolean success = super.add(pl);
+		updateMinMax();
+		return success;
+	}
+
+	public boolean add(List<Point> points) {
+		PointList pl = new PointList(points);
+		return add(pl);
+	}
+	
+	public void updateMinMax() {
+		for(PointList checkPl : this) {
+			maxX = Math.max(getMaxX(), checkPl.getMaxX());
+			maxY = Math.max(getMaxY(), checkPl.getMaxY());
+			minX = Math.min(getMinX(), checkPl.getMinX());
+			minY = Math.min(getMinY(), checkPl.getMinY());
+		}
+	}
+	
+	public double getMaxX() {
+		return maxX;
+	}
+
+	public double getMaxY() {
+		return maxY;
+	}
+
+	public double getMinX() {
+		return minX;
+	}
+
+	public double getMinY() {
+		return minY;
+	}
+	
+	public boolean hasValidMinMaxValues() {
+		return maxX > minX && maxY > minY;
+	}
+
+	public static class Converter implements IStringConverter<PointListList> {
+		@Override
+		public PointListList convert(String value) {
+			return new PointListList(value);
+		}
+	}
+
+	/**
+	 * List of Points including max values
+	 * 
+	 * @author Jens Bornschein
+	 * 
+	 */
+	public static class PointList extends ArrayList<Point> {
+
+		private static final long serialVersionUID = -2318768874799315111L;
+		private Double maxX = Double.NEGATIVE_INFINITY;
+		private Double maxY = Double.NEGATIVE_INFINITY;
+		private Double minX = Double.POSITIVE_INFINITY;
+		private Double minY = Double.POSITIVE_INFINITY;
+		private String name = "";
+
+		public PointList(List<Point> points) {
+			if (points != null && !points.isEmpty()) {
+				for (Point p : points) {
+					this.insertSorted(p);
+				}
+			}
+		}
+
+		public PointList(String points) {
+			if (points == null || points.isEmpty())
+				return;
+
+			String[] pl = points.split("::");
+
+			if (pl != null && pl.length > 0) {
+
+				String pts;
+				if (pl.length > 1) {
+					setName(pl[0].trim());
+					pts = pl[1].replaceAll("[^\\d.,^\\s+,^-]", "");
+				} else {
+					pts = pl[0].replaceAll("[^\\d.,^\\s+,^-]", "");
+				}
+				String[] s = pts.split("\\s+");
+
+				for (String string : s) {
+					if (string != null && !string.isEmpty()) {
+						Point p = (new Point.Converter()).convert(string);
+						this.insertSorted(p);
+					}
+				}
+			}
+		}
+
+		public PointList() {
+			this("");
+		}
+
+		public boolean insertSorted(Point p) {
+			maxX = Math.max(getMaxX(), p.getX());
+			maxY = Math.max(getMaxY(), p.getY());
+			minX = Math.min(getMinX(), p.getX());
+			minY = Math.min(getMinY(), p.getY());
+			boolean returnVal = super.add(p);
+			
+			Comparable<Point> cmp = (Comparable<Point>) p;
+	        for (int i = size()-1; i > 0 && cmp.compareTo(get(i-1)) < 0; i--)
+	            Collections.swap(this, i, i-1);
+	        return returnVal;
+		}
+		
+
+		@Deprecated
+		public void add(int index, Point element) {
+//			throw new UnsupportedOperationException("Only insertions via insertSorted are allowed");
+			this.insertSorted(element);
+		}
+
+		@Deprecated
+		public boolean add(Point e) {
+//			throw new UnsupportedOperationException("Only insertions via insertSorted are allowed");
+			return this.insertSorted(e);
+		}
+
+		public double getMaxX() {
+			return maxX;
+		}
+
+		public double getMaxY() {
+			return maxY;
+		}
+
+		public double getMinX() {
+			return minX;
+		}
+
+		public double getMinY() {
+			return minY;
+		}
+
+		public String getName() {
+			return name;
+		}
+
+		public void setName(String name) {
+			this.name = name;
+		}
+
+		/**
+		 * Gets the first maximum of the data set.
+		 * TODO implement multiple maxima with a proper string representation
+		 * @return first maximum point
+		 */
+		public Point getFirstMaximum() {
+			if(this.isEmpty())
+				return null;
+			
+			Point maxPoint = get(0);
+			
+			for(Point p : this) {
+				if(maxPoint.getY() < p.getY())
+					maxPoint = p;
+			}
+			
+			return maxPoint;
+		}
+		
+		/**
+		 * Gets the first minimum of the data set.
+		 * TODO implement multiple minimum with a proper string representation
+		 * @return first minimum point
+		 */
+		public Point getFirstMinimum() {
+			if(this.isEmpty())
+				return null;
+			
+			Point minPoint = get(0);
+			
+			for(Point p : this) {
+				if(minPoint.getY() > p.getY())
+					minPoint = p;
+			}
+			
+			return minPoint;
+		}
+		
+		public class Converter implements IStringConverter<PointList> {
+			@Override
+			public PointList convert(String value) {
+				return new PointList(value.trim());
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/parser/Range.java b/src/main/java/parser/Range.java
new file mode 100644
index 00000000..ddd99be3
--- /dev/null
+++ b/src/main/java/parser/Range.java
@@ -0,0 +1,117 @@
+package parser;
+
+import com.beust.jcommander.IStringConverter;
+/**
+ * 
+ * @author Gregor Harlan, Jens Bornschein
+ * Idea and supervising by Jens Bornschein jens.bornschein@tu-dresden.de
+ * Copyright by Technische Universität Dresden / MCI 2014
+ *
+ */
+public class Range {
+	/** Start of the range */
+	private double from;
+	/** End of the range */
+	private double to;
+	
+	private String name;
+
+	/**
+	 * Constructor with name.
+	 * @param from	|	start of the range
+	 * @param to	|	end of the range
+	 * @param name
+	 */
+	public Range(double from, double to, String name) {
+		this.from = from;
+		this.to = to;
+		this.name = name;
+	}
+	
+	/**
+	 * Constructor without name.
+	 * @param from	|	start of the range
+	 * @param to	|	end of the range
+	 */
+	public Range(double from, double to)  { 
+		this(from, to, "");
+	}
+
+	/**
+	 * Calculates the distance covered by the range.
+	 * @return distance
+	 */
+	public double distance() {
+		return to - from;
+	}
+
+	@Override
+	public String toString() {
+		return name + " " + from + ":" + to;
+	}
+
+	/**
+	 * Converter class for parsing ranges from strings.
+	 */
+	public static class Converter implements IStringConverter<Range> {
+		/**
+		 * Converts a range specified by a string to a {@link Range} instance.
+		 * The syntax is: {@code [["]<name>["]::]<from>:<to>[:<name>]}.
+		 * The second name parameter is preferred.
+		 * The from and to parameters should be parsable as Double.
+		 * 
+		 * @param value	|	correctly formatted range string
+		 */
+		@Override
+		public Range convert(String value) {
+			String[] parts = value.split("::");
+			String[] s;
+			String name = "";
+			
+			// Extract the name if specified and remove quotations
+			if(parts.length > 1){
+				name = parts[0].replace("\"", "").trim();
+				s = parts[1].split(":");
+			}else{
+				s = parts[0].split(":");
+			}			
+			
+			// There were not enough parameters specified.
+			if (s.length < 2)
+				return new Range(-8, 8);
+			
+			/*
+			 * If there are two parameters, use the first name string,
+			 * if there are more, use the second one.
+			 */
+			return s.length > 2 ? new Range(Double.parseDouble(s[0]),
+					Double.parseDouble(s[1]), s[2]) : new Range(
+					Double.parseDouble(s[0]), Double.parseDouble(s[1]), name);				
+			}
+		
+	}
+
+	public double getFrom() {
+		return from;
+	}
+
+	public void setFrom(double from) {
+		this.from = from;
+	}
+
+	public double getTo() {
+		return to;
+	}
+
+	public void setTo(double to) {
+		this.to = to;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+}
diff --git a/src/main/java/parser/SvgTools.java b/src/main/java/parser/SvgTools.java
new file mode 100644
index 00000000..881ef6b3
--- /dev/null
+++ b/src/main/java/parser/SvgTools.java
@@ -0,0 +1,111 @@
+package parser;
+
+import java.text.MessageFormat;
+
+public class SvgTools {
+	private SvgTools() {
+	}
+	
+	/**
+	 * Format a number for svg usage according to the constant decimalFormat
+	 * 
+	 * @param value
+	 * @return
+	 */
+	public static String format2svg(double value) {
+		return Constants.decimalFormat.format(value);
+	}
+
+	/**
+	 * Formats an additional Name of an object. Checks if the name is set. If
+	 * name is set, the name is packed into brackets and prepend with an
+	 * whitespace
+	 * 
+	 * @param name
+	 *            | optional name of an object or NULL
+	 * @return empty string or the name of the object packed into brackets and
+	 *         prepend with a whitespace e.g. ' (optional name)'
+	 */
+	public static String formatName(String name) {
+		return (name == null || name.isEmpty()) ? "" : " (" + name + ")";
+	}
+
+	/**
+	 * Try to translate a key in the localized version defined in the
+	 * PropertyResourceBundle file.
+	 * 
+	 * @param key
+	 *            | PropertyResourceBundle key
+	 * @param arguments
+	 *            | arguments that should fill the placeholder in the returned
+	 *            PropertyResourceBundle value
+	 * @return a localized string for the given PropertyResourceBundle key,
+	 *         filled with the set arguments
+	 */
+	public static String translate(String key, Object... arguments) {
+		return MessageFormat.format(Constants.bundle.getString(key), arguments);
+	}
+
+	/**
+	 * Try to translate a key in the localized version defined in the
+	 * PropertyResourceBundle file. This function is optimized for differing
+	 * sentences depending on the amount of results.
+	 * 
+	 * @param key
+	 *            | PropertyResourceBundle key
+	 * @param arguments
+	 *            | arguments that should fill the placeholder in the returned
+	 *            PropertyResourceBundle value. The last argument gives the
+	 *            count and decide which value will be returned.
+	 * @return a localized string for the given amount depending
+	 *         PropertyResourceBundle key, filled with the set arguments
+	 */
+	public static String translateN(String key, Object... arguments) {
+		int last = (int) arguments[arguments.length - 1];
+		String suffix = last == 0 ? "_0" : last == 1 ? "_1" : "_n";
+		return translate(key + suffix, arguments);
+	}
+
+	/**
+	 * Formats a Point that it is optimized for textual output and packed into
+	 * the caption with brackets. E.g. E(x | y)
+	 * 
+	 * @param cs
+	 *            the coordinate system
+	 * @param point
+	 *            The point that should be transformed into a textual
+	 *            representation
+	 * @param cap
+	 *            The caption string without brackets
+	 * @return formated string for the point with '/' as delimiter if now
+	 *         caption is set, otherwise packed in the caption with brackets and
+	 *         the '|' as delimiter
+	 */
+	public static String formatForText(CoordinateSystem cs, Point point, String cap) {
+		String p = cs.formatX(point.getX()) + " | " + cs.formatY(point.getY());
+		String capTrimmed = cap.trim();
+		return (capTrimmed != null && !capTrimmed.isEmpty()) ? capTrimmed + "(" + p + ")" : p;
+	}
+
+	/**
+	 * Try to translate the function index into a continuous literal starting
+	 * with the char 'f'. If the given index is not valid it returns the name as
+	 * a combination of 'f' + the given number.
+	 * 
+	 * @param f
+	 *            | the index if the function
+	 * @return a literal representation to the given function index e.g. 'f',
+	 *         'g', 'h' or 'f1000'.
+	 */
+	public static String getFunctionName(int f) {
+		if (f < 0 || f > (Constants.FN_LIST.size() - 1))
+			return "f" + f;
+		return Constants.FN_LIST.get(f);
+	}
+
+	public static String getPointName(int p) {
+		if (p < 0 || p > (Constants.PN_LIST.size() - 1))
+			return "P" + p;
+		return Constants.PN_LIST.get(p);
+	}
+}
diff --git a/src/main/java/parser/XType.java b/src/main/java/parser/XType.java
new file mode 100644
index 00000000..a162d519
--- /dev/null
+++ b/src/main/java/parser/XType.java
@@ -0,0 +1,8 @@
+package parser;
+
+/**
+ * Determines whether the x values are metric or categorial.
+ */
+public enum XType {
+	METRIC, CATEGORIAL
+}
\ No newline at end of file
diff --git a/src/main/java/parser/package-info.java b/src/main/java/parser/package-info.java
new file mode 100644
index 00000000..c0234d3b
--- /dev/null
+++ b/src/main/java/parser/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * CSV parsing
+ */
+package parser;
\ No newline at end of file
-- 
GitLab