From b3ecab7d3f0ff220acc5361dec397a8830fb30c6 Mon Sep 17 00:00:00 2001
From: Tim Molter <tim.molter@gmail.com>
Date: Sat, 30 Jul 2011 17:07:04 +0200
Subject: [PATCH] release 1.0.2

---
 build.properties                         |  2 +-
 sample/com/xeiam/examples/Example4.java  |  2 +-
 sample/com/xeiam/examples/Example5.java  | 45 ++++++++++++++++++++++++
 sample/com/xeiam/examples/Example6.java  | 44 +++++++++++++++++++++++
 sample/com/xeiam/examples/Example7.java  | 44 +++++++++++++++++++++++
 src/com/xeiam/xcharts/Axis.java          |  8 ++---
 src/com/xeiam/xcharts/AxisPair.java      | 43 ++++++++++++++++++++++
 src/com/xeiam/xcharts/AxisTick.java      | 40 +++++++++++----------
 src/com/xeiam/xcharts/Chart.java         |  5 +++
 src/com/xeiam/xcharts/PlotContent.java   | 18 +++++-----
 src/com/xeiam/xcharts/series/Series.java | 41 ++++++++++++++-------
 11 files changed, 245 insertions(+), 47 deletions(-)
 create mode 100644 sample/com/xeiam/examples/Example5.java
 create mode 100644 sample/com/xeiam/examples/Example6.java
 create mode 100644 sample/com/xeiam/examples/Example7.java

diff --git a/build.properties b/build.properties
index 1439ef75..e2a43317 100644
--- a/build.properties
+++ b/build.properties
@@ -1,5 +1,5 @@
 project.name=xchart
-build.version=1.0.1
+build.version=1.0.2
 lib.dir=lib
 src.dir=src
 web.dir=web
diff --git a/sample/com/xeiam/examples/Example4.java b/sample/com/xeiam/examples/Example4.java
index 9dd25ac6..2d4cf67a 100644
--- a/sample/com/xeiam/examples/Example4.java
+++ b/sample/com/xeiam/examples/Example4.java
@@ -51,7 +51,7 @@ public class Example4 {
     private static double[] getRandomWalk(int numPoints) {
 
         double[] y = new double[numPoints];
-        y[0] = -1000;
+        y[0] = 0;
         for (int i = 1; i < y.length; i++) {
             y[i] = y[i - 1] + Math.random() - .5;
         }
diff --git a/sample/com/xeiam/examples/Example5.java b/sample/com/xeiam/examples/Example5.java
new file mode 100644
index 00000000..f0a9934a
--- /dev/null
+++ b/sample/com/xeiam/examples/Example5.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright 2011 Xeiam LLC.
+ *
+ * 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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 com.xeiam.examples;
+
+import com.xeiam.swing.SwingWrapper;
+import com.xeiam.xcharts.Chart;
+
+/**
+ * Plot vertical and horizontal lines
+ * 
+ * @author timmolter
+ */
+public class Example5 {
+
+    public static void main(String[] args) {
+
+        // Create Chart
+        Chart chart = new Chart(700, 500);
+
+        // Customize Chart
+        chart.setChartTitle("Sample Chart");
+        chart.setXAxisTitle("X");
+        chart.setYAxisTitle("Y");
+
+        chart.addSeries("vertical", new double[] { 1, 1 }, new double[] { -10, 10 });
+        chart.addSeries("horizontal", new double[] { -10, 10 }, new double[] { 0, 0 });
+
+        SwingWrapper swingHelper = new SwingWrapper(chart);
+        swingHelper.displayChart();
+    }
+
+}
diff --git a/sample/com/xeiam/examples/Example6.java b/sample/com/xeiam/examples/Example6.java
new file mode 100644
index 00000000..f0b6c77d
--- /dev/null
+++ b/sample/com/xeiam/examples/Example6.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright 2011 Xeiam LLC.
+ *
+ * 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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 com.xeiam.examples;
+
+import com.xeiam.swing.SwingWrapper;
+import com.xeiam.xcharts.Chart;
+
+/**
+ * Create chart with single point
+ * 
+ * @author timmolter
+ */
+public class Example6 {
+
+    public static void main(String[] args) {
+
+        // Create Chart
+        Chart chart = new Chart(700, 500);
+
+        // Customize Chart
+        chart.setChartTitle("Sample Chart");
+        chart.setXAxisTitle("X");
+        chart.setYAxisTitle("Y");
+
+        chart.addSeries("single point (1,1)", new double[] { 1 }, new double[] { 1 });
+
+        SwingWrapper swingHelper = new SwingWrapper(chart);
+        swingHelper.displayChart();
+    }
+
+}
diff --git a/sample/com/xeiam/examples/Example7.java b/sample/com/xeiam/examples/Example7.java
new file mode 100644
index 00000000..c294d43d
--- /dev/null
+++ b/sample/com/xeiam/examples/Example7.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright 2011 Xeiam LLC.
+ *
+ * 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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 com.xeiam.examples;
+
+import com.xeiam.swing.SwingWrapper;
+import com.xeiam.xcharts.Chart;
+
+/**
+ * Create chart with NaN values
+ * 
+ * @author timmolter
+ */
+public class Example7 {
+
+    public static void main(String[] args) {
+
+        // Create Chart
+        Chart chart = new Chart(700, 500);
+
+        // Customize Chart
+        chart.setChartTitle("Sample Chart");
+        chart.setXAxisTitle("X");
+        chart.setYAxisTitle("Y");
+
+        chart.addSeries("NaN Value at (2,2)", null, new double[] { 0, 1, Double.NaN, 3, 4 });
+
+        SwingWrapper swingHelper = new SwingWrapper(chart);
+        swingHelper.displayChart();
+    }
+
+}
diff --git a/src/com/xeiam/xcharts/Axis.java b/src/com/xeiam/xcharts/Axis.java
index da921887..38888f25 100644
--- a/src/com/xeiam/xcharts/Axis.java
+++ b/src/com/xeiam/xcharts/Axis.java
@@ -47,9 +47,9 @@ public class Axis implements IChartPart {
     /** the axis direction */
     private Direction direction;
 
-    private double min = Double.MAX_VALUE;
+    private Double min = null;
 
-    private double max = -Double.MAX_VALUE;
+    private Double max = null;
 
     /** the bounds */
     private Rectangle bounds = new Rectangle(); // default all-zero rectangle
@@ -93,10 +93,10 @@ public class Axis implements IChartPart {
         // System.out.println(min);
         // System.out.println(max);
 
-        if (min < this.min) {
+        if (this.min == null || min < this.min) {
             this.min = min;
         }
-        if (max > this.max) {
+        if (this.max == null || max > this.max) {
             this.max = max;
         }
 
diff --git a/src/com/xeiam/xcharts/AxisPair.java b/src/com/xeiam/xcharts/AxisPair.java
index 6fe117e3..c488cc11 100644
--- a/src/com/xeiam/xcharts/AxisPair.java
+++ b/src/com/xeiam/xcharts/AxisPair.java
@@ -58,16 +58,42 @@ public class AxisPair implements IChartPart {
      */
     public Series addSeries(String seriesName, double[] xData, double[] yData) {
 
+        // Sanity checks
+        if (yData == null) {
+            throw new RuntimeException("Y-Axis data cannot be null!!!");
+        }
+        if (yData.length == 0) {
+            throw new RuntimeException("Y-Axis data cannot be empty!!!");
+        }
+        if (xData != null && xData.length == 0) {
+            throw new RuntimeException("X-Axis data cannot be empty!!!");
+        }
+        if (xData != null && xData.length == 1 && Double.isNaN(yData[0])) {
+            throw new RuntimeException("X-Axis data cannot contain a single NaN value!!!");
+        }
+        if (yData.length == 1 && Double.isNaN(yData[0])) {
+            throw new RuntimeException("Y-Axis data cannot contain a single NaN value!!!");
+        }
+
         Series series;
         if (xData != null) {
+            verifyValues(xData);
+            verifyValues(yData);
             series = new Series(seriesName, xData, yData);
         } else { // generate xData
             double[] generatedXData = new double[yData.length];
+            verifyValues(yData);
             for (int i = 1; i < yData.length; i++) {
                 generatedXData[i] = i;
             }
             series = new Series(seriesName, generatedXData, yData);
         }
+
+        // Sanity check
+        if (xData != null && xData.length != yData.length) {
+            throw new RuntimeException("X and Y-Axis lengths are not the same!!! ");
+        }
+
         seriesMap.put(seriesCount++, series);
 
         // add min/max to axis
@@ -77,6 +103,22 @@ public class AxisPair implements IChartPart {
         return series;
     }
 
+    /**
+     * Checks for invalid values in data array
+     * 
+     * @param data
+     */
+    private void verifyValues(double[] data) {
+
+        for (int i = 0; i < data.length; i++) {
+            if (data[i] == Double.POSITIVE_INFINITY) {
+                throw new RuntimeException("Axis data cannot contain Double.POSITIVE_INFINITY!!!");
+            } else if (data[i] == Double.NEGATIVE_INFINITY) {
+                throw new RuntimeException("Axis data cannot contain Double.NEGATIVE_INFINITY!!!");
+            }
+        }
+    }
+
     protected Axis getXAxis() {
         return xAxis;
     }
@@ -111,6 +153,7 @@ public class AxisPair implements IChartPart {
 
     @Override
     public void paint(Graphics2D g) {
+
         yAxis.paint(g);
         xAxis.paint(g);
     }
diff --git a/src/com/xeiam/xcharts/AxisTick.java b/src/com/xeiam/xcharts/AxisTick.java
index d74d6176..0319132c 100644
--- a/src/com/xeiam/xcharts/AxisTick.java
+++ b/src/com/xeiam/xcharts/AxisTick.java
@@ -148,30 +148,32 @@ public class AxisTick implements IChartPart {
 
         int margin = AxisPair.getMargin(workingSpace, tickSpace);
 
-        final BigDecimal MIN = new BigDecimal(new Double(axis.getMin()).toString());
-        BigDecimal firstPosition;
-        BigDecimal gridStep = getGridStep(tickSpace);
-
-        double xyz = MIN.remainder(gridStep).doubleValue();
-        if (xyz <= 0.0) {
-            firstPosition = MIN.subtract(MIN.remainder(gridStep));
+        // a check if all axis data are the exact same values
+        if (axis.getMax() == axis.getMin()) {
+            tickLabels.add(format(axis.getMax()));
+            tickLocations.add((int) (margin + tickSpace / 2.0));
         } else {
-            firstPosition = MIN.subtract(MIN.remainder(gridStep)).add(gridStep);
-        }
-
-        for (BigDecimal b = firstPosition; b.doubleValue() <= axis.getMax(); b = b.add(gridStep)) {
 
-            // System.out.println("b= " + b);
-            tickLabels.add(format(b.doubleValue()));
-            int tickLabelPosition = (int) (margin + ((b.doubleValue() - axis.getMin()) / (axis.getMax() - axis.getMin()) * tickSpace));
-            // System.out.println("tickLabelPosition= " + tickLabelPosition);
+            final BigDecimal MIN = new BigDecimal(new Double(axis.getMin()).toString());
+            BigDecimal firstPosition;
+            BigDecimal gridStep = getGridStep(tickSpace);
 
-            // a check if all axis data are the exact same values
-            if (Math.abs(axis.getMax() - axis.getMin()) / 5 == 0.0) {
-                tickLabelPosition = (int) (margin + tickSpace / 2.0);
+            double xyz = MIN.remainder(gridStep).doubleValue();
+            if (xyz <= 0.0) {
+                firstPosition = MIN.subtract(MIN.remainder(gridStep));
+            } else {
+                firstPosition = MIN.subtract(MIN.remainder(gridStep)).add(gridStep);
             }
 
-            tickLocations.add(tickLabelPosition);
+            for (BigDecimal b = firstPosition; b.doubleValue() <= axis.getMax(); b = b.add(gridStep)) {
+
+                // System.out.println("b= " + b);
+                tickLabels.add(format(b.doubleValue()));
+                int tickLabelPosition = (int) (margin + ((b.doubleValue() - axis.getMin()) / (axis.getMax() - axis.getMin()) * tickSpace));
+                // System.out.println("tickLabelPosition= " + tickLabelPosition);
+
+                tickLocations.add(tickLabelPosition);
+            }
         }
     }
 
diff --git a/src/com/xeiam/xcharts/Chart.java b/src/com/xeiam/xcharts/Chart.java
index f93caa87..1722e903 100644
--- a/src/com/xeiam/xcharts/Chart.java
+++ b/src/com/xeiam/xcharts/Chart.java
@@ -51,6 +51,11 @@ public class Chart {
 
     public void paint(final Graphics2D g) {
 
+        // Sanity check
+        if (axisPair.getSeriesMap().isEmpty()) {
+            throw new RuntimeException("No series defined for Chart!!!");
+        }
+
         g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // global rendering hint
         g.setColor(ChartColor.getAWTColor(ChartColor.GREY));
         g.fillRect(0, 0, width, height);
diff --git a/src/com/xeiam/xcharts/PlotContent.java b/src/com/xeiam/xcharts/PlotContent.java
index 6f645604..9446d921 100644
--- a/src/com/xeiam/xcharts/PlotContent.java
+++ b/src/com/xeiam/xcharts/PlotContent.java
@@ -72,15 +72,15 @@ public class PlotContent implements IChartPart {
 
             for (int i = 0; i < xData.length; i++) {
 
-                // if (Double.isInfinite(xData[i]) || Double.isNaN(xData[i])) {
-                // throw new RuntimeException("Infinite or NaN values in xAxis Data not allowed!!!");
-                // }
-                //
-                // if (Double.isInfinite(yData[i]) || Double.isNaN(yData[i])) {
-                // throw new RuntimeException("Infinite or NaN values in yAxis Data not allowed!!!");
-                // }
-
-                if (!Double.isInfinite(xData[i]) && !Double.isNaN(xData[i]) && !Double.isInfinite(yData[i]) && !Double.isNaN(yData[i])) {
+                if (Double.isInfinite(xData[i])) {
+                    throw new RuntimeException("Infinite values in xAxis Data not allowed!!!");
+                }
+
+                if (Double.isInfinite(yData[i])) {
+                    throw new RuntimeException("Infinite values in yAxis Data not allowed!!!");
+                }
+
+                if (!Double.isNaN(xData[i]) && !Double.isNaN(yData[i])) {
 
                     int xTransform = (int) (xLeftMargin + ((xData[i] - xMin) / (xMax - xMin) * xTickSpace));
                     int yTransform = (int) (bounds.getHeight() - (yTopMargin + (yData[i] - yMin) / (yMax - yMin) * yTickSpace));
diff --git a/src/com/xeiam/xcharts/series/Series.java b/src/com/xeiam/xcharts/series/Series.java
index c15c5a74..4e1b47cf 100644
--- a/src/com/xeiam/xcharts/series/Series.java
+++ b/src/com/xeiam/xcharts/series/Series.java
@@ -17,7 +17,6 @@ package com.xeiam.xcharts.series;
 
 import java.awt.BasicStroke;
 import java.awt.Color;
-import java.util.Arrays;
 
 import com.xeiam.xcharts.series.markers.Marker;
 
@@ -33,16 +32,16 @@ public class Series {
     protected double[] yData;
 
     /** the minimum value of axis range */
-    private double xMin = 0d;
+    private double xMin;
 
     /** the maximum value of axis range */
-    private double xMax = 1d;
+    private double xMax;
 
     /** the minimum value of axis range */
-    private double yMin = 0d;
+    private double yMin;
 
     /** the maximum value of axis range */
-    private double yMax = 1d;
+    private double yMax;
 
     /** Line Style */
     private BasicStroke stroke;
@@ -70,16 +69,14 @@ public class Series {
         this.yData = yData;
 
         // xData
-        double[] xDataClone = xData.clone();
-        Arrays.sort(xDataClone);
-        this.xMin = xDataClone[0];
-        this.xMax = xDataClone[xDataClone.length - 1];
+        double[] xMinMax = findMinMax(xData);
+        this.xMin = xMinMax[0];
+        this.xMax = xMinMax[1];
 
         // yData
-        double[] yDataClone = yData.clone();
-        Arrays.sort(yDataClone);
-        this.yMin = yDataClone[0];
-        this.yMax = yDataClone[yDataClone.length - 1];
+        double[] yMinMax = findMinMax(yData);
+        this.yMin = yMinMax[0];
+        this.yMax = yMinMax[1];
         // System.out.println(yMin);
         // System.out.println(yMax);
 
@@ -92,6 +89,24 @@ public class Series {
 
     }
 
+    private double[] findMinMax(double[] data) {
+        Double min = null;
+        Double max = null;
+        for (int i = 0; i < data.length; i++) {
+            if (min == null || data[i] < min) {
+                if (!Double.isNaN(data[i])) {
+                    min = data[i];
+                }
+            }
+            if (max == null || data[i] > max) {
+                if (!Double.isNaN(data[i])) {
+                    max = data[i];
+                }
+            }
+        }
+        return new double[] { min, max };
+    }
+
     public String getName() {
         return name;
     }
-- 
GitLab