From 0eb14cc3e78127db858a36d4479dc8e9c0d46184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Georg=20Gra=C3=9Fnick?= <georg.grassnick@mailbox.tu-dresden.de> Date: Thu, 8 Aug 2019 21:15:43 +0200 Subject: [PATCH] Add own XAlignedCategories parser --- .../de/tudresden/inf/mci/brailleplot/App.java | 6 +- .../brailleplot/csvparser/CsvDotParser.java | 2 +- .../csvparser/CsvParseAlgorithm.java | 7 +- .../mci/brailleplot/csvparser/CsvParser.java | 19 +-- .../CsvXAlignedCategoriesParser.java | 118 +++++++----------- .../csvparser/CsvXAlignedParser.java | 2 +- ...mpleCategoricalPointListContainerImpl.java | 11 ++ ...v => 0_bar_chart_categorical_vertical.csv} | 0 8 files changed, 78 insertions(+), 87 deletions(-) rename src/main/resources/examples/csv/{0_bar_chart_categorical_horizontal.csv => 0_bar_chart_categorical_vertical.csv} (100%) 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 d6fe60d5..fa831a78 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/App.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/App.java @@ -11,8 +11,8 @@ import de.tudresden.inf.mci.brailleplot.configparser.Printer; import de.tudresden.inf.mci.brailleplot.csvparser.CsvOrientation; import de.tudresden.inf.mci.brailleplot.csvparser.CsvParser; import de.tudresden.inf.mci.brailleplot.csvparser.CsvType; +import de.tudresden.inf.mci.brailleplot.datacontainers.CategoricalPointListContainer; import de.tudresden.inf.mci.brailleplot.datacontainers.PointList; -import de.tudresden.inf.mci.brailleplot.datacontainers.PointListContainer; import de.tudresden.inf.mci.brailleplot.diagrams.BarChart; import de.tudresden.inf.mci.brailleplot.printabledata.SimpleMatrixDataImpl; import de.tudresden.inf.mci.brailleplot.rendering.MasterRenderer; @@ -151,11 +151,11 @@ public final class App { // Parse csv data ClassLoader classloader = Thread.currentThread().getContextClassLoader(); - InputStream csvStream = classloader.getResourceAsStream("examples/csv/0_bar_chart.csv"); + InputStream csvStream = classloader.getResourceAsStream("examples/csv/0_bar_chart_categorical_vertical.csv"); Reader csvReader = new BufferedReader(new InputStreamReader(csvStream)); CsvParser csvParser = new CsvParser(csvReader, ',', '\"'); - PointListContainer<PointList> container = csvParser.parse(CsvType.X_ALIGNED, CsvOrientation.VERTICAL); + CategoricalPointListContainer<PointList> container = csvParser.parse(CsvType.X_ALIGNED_CATEGORIES, CsvOrientation.VERTICAL); mLogger.debug("Internal data representation:\n {}", container.toString()); BarChart barChart = new BarChart(container); diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/csvparser/CsvDotParser.java b/src/main/java/de/tudresden/inf/mci/brailleplot/csvparser/CsvDotParser.java index 351d4667..ee3dfab1 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/csvparser/CsvDotParser.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/csvparser/CsvDotParser.java @@ -16,7 +16,7 @@ import java.util.Objects; * @author SVGPlott-Team, Georg Graßnick * @version 2019.07.29 */ -public class CsvDotParser extends CsvParseAlgorithm { +public class CsvDotParser extends CsvParseAlgorithm<PointListContainer<PointList>> { /** * Parses scattered point data in horizontal data sets, alternating mX and mY. The diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/csvparser/CsvParseAlgorithm.java b/src/main/java/de/tudresden/inf/mci/brailleplot/csvparser/CsvParseAlgorithm.java index 9ed81867..1d6109db 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/csvparser/CsvParseAlgorithm.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/csvparser/CsvParseAlgorithm.java @@ -14,10 +14,11 @@ import java.util.Objects; /** * An algorithm for parsing CSV data. Contains implementations for two * orientations of the data in the file. + * @param <T> The type of PointContainer, that is parsed to. * @author SVGPlott-Team, Georg Graßnick * @version 2019.07.29 */ -public abstract class CsvParseAlgorithm { +public abstract class CsvParseAlgorithm<T extends PointListContainer<PointList>> { protected final Logger mLogger = LoggerFactory.getLogger(getClass()); @@ -27,7 +28,7 @@ public abstract class CsvParseAlgorithm { * @param csvData The parsed input String. * @return A {@link PointListContainer}{@literal <PointList>} representing the data. */ - public abstract PointListContainer<PointList> parseAsHorizontalDataSets(List<? extends List<String>> csvData); + public abstract T parseAsHorizontalDataSets(List<? extends List<String>> csvData); /** * If the data sets are oriented horizontally, i.e. in rows, parse the rows into @@ -35,7 +36,7 @@ public abstract class CsvParseAlgorithm { * @param csvData The parsed input String. * @return A {@link PointListContainer}{@literal <}{@link PointList}{@literal >} representing the data. */ - public abstract PointListContainer<PointList> parseAsVerticalDataSets(List<? extends List<String>> csvData); + public abstract T parseAsVerticalDataSets(List<? extends List<String>> csvData); /** * Adds a {@link Point2DDouble} to a {@link PointList} in a {@link PointListContainer}{@literal <}{@link PointList}{@literal >}, diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/csvparser/CsvParser.java b/src/main/java/de/tudresden/inf/mci/brailleplot/csvparser/CsvParser.java index d98a8345..98f67fae 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/csvparser/CsvParser.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/csvparser/CsvParser.java @@ -8,7 +8,6 @@ import de.tudresden.inf.mci.brailleplot.datacontainers.PointListContainer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.io.IOException; import java.io.Reader; import java.util.ArrayList; @@ -20,7 +19,7 @@ import java.util.Objects; * @author SVGPlott-Team, Georg Graßnick * @version 2019.07.29 */ -public class CsvParser { +public final class CsvParser { private final Logger mLogger = LoggerFactory.getLogger(CsvParser.class); @@ -56,27 +55,29 @@ public class CsvParser { /** * Chooses the right parsing algorithm. + * Casting in this method is not guaranteed to be safe, so use at your own risk. * @param csvType CsvType * @param csvOrientation CsvOrientation * @return PointListList */ - public PointListContainer<PointList> parse(final CsvType csvType, final CsvOrientation csvOrientation) { - CsvParseAlgorithm csvParseAlgorithm; + @SuppressWarnings("unchecked") + public <T extends PointListContainer<PointList>> T parse(final CsvType csvType, final CsvOrientation csvOrientation) { + CsvParseAlgorithm<T> csvParseAlgorithm; mLogger.debug("Parsing data as \"{}\", orientation \"{}\"", csvType, csvOrientation); switch (csvType) { case DOTS: - csvParseAlgorithm = new CsvDotParser(); + csvParseAlgorithm = ((CsvParseAlgorithm<T>) new CsvDotParser()); break; case X_ALIGNED: - csvParseAlgorithm = new CsvXAlignedParser(); + csvParseAlgorithm = ((CsvParseAlgorithm<T>) new CsvXAlignedParser()); break; case X_ALIGNED_CATEGORIES: - csvParseAlgorithm = new CsvXAlignedCategoriesParser(); + csvParseAlgorithm = ((CsvParseAlgorithm<T>) new CsvXAlignedCategoriesParser()); break; default: - return null; + throw new UnsupportedOperationException(); } switch (csvOrientation) { @@ -85,7 +86,7 @@ public class CsvParser { case VERTICAL: return csvParseAlgorithm.parseAsVerticalDataSets(mCsvData); default: - return null; + throw new UnsupportedOperationException(); } } } diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/csvparser/CsvXAlignedCategoriesParser.java b/src/main/java/de/tudresden/inf/mci/brailleplot/csvparser/CsvXAlignedCategoriesParser.java index d696d7f8..d468e89a 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/csvparser/CsvXAlignedCategoriesParser.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/csvparser/CsvXAlignedCategoriesParser.java @@ -1,8 +1,8 @@ package de.tudresden.inf.mci.brailleplot.csvparser; +import de.tudresden.inf.mci.brailleplot.datacontainers.CategoricalPointListContainer; import de.tudresden.inf.mci.brailleplot.datacontainers.PointList; -import de.tudresden.inf.mci.brailleplot.datacontainers.PointListContainer; -import de.tudresden.inf.mci.brailleplot.datacontainers.SimplePointListContainerImpl; +import de.tudresden.inf.mci.brailleplot.datacontainers.SimpleCategoricalPointListContainerImpl; import de.tudresden.inf.mci.brailleplot.datacontainers.SimplePointListImpl; import de.tudresden.inf.mci.brailleplot.point.Point2DDouble; @@ -17,13 +17,13 @@ import java.util.Objects; * @author SVGPlott-Team, Georg Graßnick * @version 2019.07.29 */ -public class CsvXAlignedCategoriesParser extends CsvParseAlgorithm { +public class CsvXAlignedCategoriesParser extends CsvParseAlgorithm<CategoricalPointListContainer<PointList>> { @Override - public PointListContainer<PointList> parseAsHorizontalDataSets(final List<? extends List<String>> csvData) { + public CategoricalPointListContainer<PointList> parseAsHorizontalDataSets(final List<? extends List<String>> csvData) { Objects.requireNonNull(csvData); - PointListContainer<PointList> container = new SimplePointListContainerImpl(); + CategoricalPointListContainer<PointList> container = new SimpleCategoricalPointListContainerImpl(); Iterator<? extends List<String>> rowIterator = csvData.iterator(); @@ -33,6 +33,12 @@ public class CsvXAlignedCategoriesParser extends CsvParseAlgorithm { Iterator<String> lineIterator = rowIterator.next().iterator(); + // Move the iterator to the first category name + if (!lineIterator.hasNext()) { + return container; + } + + lineIterator.next(); if (!lineIterator.hasNext()) { return container; @@ -53,11 +59,6 @@ public class CsvXAlignedCategoriesParser extends CsvParseAlgorithm { if (!lineIterator.hasNext()) { continue; } - - if (!categoriesIt.hasNext()) { - continue; - } - String category = categoriesIt.next(); PointList pointList = new SimplePointListImpl(category); container.pushBack(pointList); @@ -90,73 +91,50 @@ public class CsvXAlignedCategoriesParser extends CsvParseAlgorithm { } @Override - public PointListContainer<PointList> parseAsVerticalDataSets(final List<? extends List<String>> csvData) { + public CategoricalPointListContainer<PointList> parseAsVerticalDataSets(final List<? extends List<String>> csvData) { Objects.requireNonNull(csvData); - PointListContainer<PointList> container = new SimplePointListContainerImpl(); - Iterator<? extends List<String>> rowIterator = csvData.iterator(); - - - if (!rowIterator.hasNext()) { - return container; - } - - Iterator<String> lineIterator = rowIterator.next().iterator(); - - // Move the iterator to the first title - /*if (!lineIterator.hasNext()) { - return container; - } - - lineIterator.next();*/ + CategoricalPointListContainer<PointList> container = new SimpleCategoricalPointListContainerImpl(); + Iterator<? extends List<String>> rowIt = csvData.iterator(); - if (!lineIterator.hasNext()) { - return container; - } + int rowNum = 0; // Keep track of the row number, so that we can include the erroneous row number in the exception. + while (rowIt.hasNext()) { + Iterator<String> lineIt = rowIt.next().iterator(); + rowNum++; - // Add a PointList for each title - while (lineIterator.hasNext()) { - PointList pointList = new SimplePointListImpl(); - pointList.setName(lineIterator.next()); - container.pushBack(pointList); - } - - // Add the data - Iterator<PointList> it = container.iterator(); - int categoryCounter = 0; - while (rowIterator.hasNext()) { - lineIterator = rowIterator.next().iterator(); - if (!lineIterator.hasNext()) { - categoryCounter++; - continue; - } - - // Find out the category title - String currentCategory = lineIterator.next(); - if (it.hasNext()) { - it.next().setName(currentCategory); - } - - // Find out the mY values and add the points to the respective lists - int currentDataSet = 0; - while (lineIterator.hasNext()) { - Number yValue; - try { - yValue = Constants.NUMBER_FORMAT.parse(lineIterator.next()); - } catch (ParseException e) { - currentDataSet++; - continue; + // Check if we are in the first line, were all the categories are defined ... + if (rowNum == 1) { + while (lineIt.hasNext()) { + container.pushBackCategory(lineIt.next()); } - - Point2DDouble newPoint = new Point2DDouble(categoryCounter, yValue.doubleValue()); - addPointToPointListList(container, currentDataSet, newPoint); - currentDataSet++; + // ... or if we are in a row, were the actual data sets are defined + } else { + // Get the name for the values of a data set + if (!lineIt.hasNext()) { + throw new MalformedCsvException("Line: " + rowNum + ": Data set must contain a name"); + } + String name = lineIt.next().trim(); + PointList pl = new SimplePointListImpl(name); + + // Parse all values + // Set the x value of each Point to the index of the category, they belong to + int columnNum = 0; + while (lineIt.hasNext()) { + columnNum++; + String value = lineIt.next().trim(); + + Number val; + try { + val = Constants.NUMBER_FORMAT.parse(value); + } catch (final ParseException pe) { + throw new MalformedCsvException("Line: " + rowNum + ": Could not parse value", pe); + } + Point2DDouble p = new Point2DDouble(columnNum, val.doubleValue()); + pl.pushBack(p); + } + container.pushBack(pl); } - - categoryCounter++; } - // TODO First add points to PointList, then add PointList to PointListContainer, so that there is no need for a calculateExtrema call - container.calculateExtrema(); return container; } diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/csvparser/CsvXAlignedParser.java b/src/main/java/de/tudresden/inf/mci/brailleplot/csvparser/CsvXAlignedParser.java index 1b1b54d7..c38e69a4 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/csvparser/CsvXAlignedParser.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/csvparser/CsvXAlignedParser.java @@ -17,7 +17,7 @@ import java.util.Objects; * @author SVGPlott-Team, Georg Graßnick * @version 2019.07.29 */ -public class CsvXAlignedParser extends CsvParseAlgorithm { +public class CsvXAlignedParser extends CsvParseAlgorithm<PointListContainer<PointList>> { @Override public PointListContainer<PointList> parseAsHorizontalDataSets(final List<? extends List<String>> csvData) { diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/datacontainers/SimpleCategoricalPointListContainerImpl.java b/src/main/java/de/tudresden/inf/mci/brailleplot/datacontainers/SimpleCategoricalPointListContainerImpl.java index f83c5f8a..834e3b3a 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/datacontainers/SimpleCategoricalPointListContainerImpl.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/datacontainers/SimpleCategoricalPointListContainerImpl.java @@ -51,4 +51,15 @@ public class SimpleCategoricalPointListContainerImpl extends SimplePointListCont } return mCategories.get(index); } + + @Override + protected String toRecursiveString(final int depth) { + StringBuilder sb = new StringBuilder(); + sb.append("Categories:\n"); + for (String s : mCategories) { + sb.append(s).append("\n"); + } + sb.append(super.toRecursiveString(depth)); + return sb.toString(); + } } diff --git a/src/main/resources/examples/csv/0_bar_chart_categorical_horizontal.csv b/src/main/resources/examples/csv/0_bar_chart_categorical_vertical.csv similarity index 100% rename from src/main/resources/examples/csv/0_bar_chart_categorical_horizontal.csv rename to src/main/resources/examples/csv/0_bar_chart_categorical_vertical.csv -- GitLab