diff --git a/src/main/java/com/xeiam/xchart/Axis.java b/src/main/java/com/xeiam/xchart/Axis.java index 2519c3efff561d24dd7b2697d9cb70f38f7b4bb7..e7722f69ea28f63032fc4d5bd5d9bd1d18862a3d 100644 --- a/src/main/java/com/xeiam/xchart/Axis.java +++ b/src/main/java/com/xeiam/xchart/Axis.java @@ -151,8 +151,8 @@ public class Axis implements IChartPart { } /** - * - */ + * @return + */ public int getSizeHint() { if (direction == Direction.X) { // X-Axis diff --git a/src/main/java/com/xeiam/xchart/AxisPair.java b/src/main/java/com/xeiam/xchart/AxisPair.java index 2c599cbd55acf6580858bd50e6515d86364ea9c7..d332384c261b82562543d5599735f4650cd3c9b7 100644 --- a/src/main/java/com/xeiam/xchart/AxisPair.java +++ b/src/main/java/com/xeiam/xchart/AxisPair.java @@ -58,7 +58,7 @@ public class AxisPair implements IChartPart { * @param xData * @param yData */ - public Series addSeries(String seriesName, Collection<Number> xData, Collection<Number> yData) { + public Series addSeries(String seriesName, Collection<Number> xData, Collection<Number> yData, Collection<Number> errorBars) { // Sanity checks if (seriesName == null) { @@ -82,18 +82,21 @@ public class AxisPair implements IChartPart { Series series; if (xData != null) { - series = new Series(seriesName, xData, yData); + series = new Series(seriesName, xData, yData, errorBars); } else { // generate xData Collection<Number> generatedXData = new ArrayList<Number>(); for (int i = 1; i < yData.size(); i++) { generatedXData.add(i); } - series = new Series(seriesName, generatedXData, yData); + series = new Series(seriesName, generatedXData, yData, errorBars); } // Sanity check if (xData != null && xData.size() != yData.size()) { - throw new IllegalArgumentException("X and Y-Axis lengths are not the same!!! "); + throw new IllegalArgumentException("X and Y-Axis sizes are not the same!!! "); + } + if (errorBars != null && errorBars.size() != yData.size()) { + throw new IllegalArgumentException("errorbars and Y-Axis sizes are not the same!!! "); } seriesMap.put(seriesCount++, series); diff --git a/src/main/java/com/xeiam/xchart/AxisTick.java b/src/main/java/com/xeiam/xchart/AxisTick.java index f7c9820f3dc2c0d9751f62853a11764629b0a600..f307131b199712d50182f289838062ff34180329 100644 --- a/src/main/java/com/xeiam/xchart/AxisTick.java +++ b/src/main/java/com/xeiam/xchart/AxisTick.java @@ -25,7 +25,6 @@ import java.util.List; import com.xeiam.xchart.interfaces.IChartPart; - /** * An axis tick. */ @@ -145,8 +144,8 @@ public class AxisTick implements IChartPart { } /** - * - */ + * + */ private void determineAxisTick() { // System.out.println("workingSpace= " + workingSpace); diff --git a/src/main/java/com/xeiam/xchart/Chart.java b/src/main/java/com/xeiam/xchart/Chart.java index 463c3750798aa1ae085e1bfda6fab4e227d942b4..2fa9efb513500d368a3be892eff6bd09f78ac53e 100644 --- a/src/main/java/com/xeiam/xchart/Chart.java +++ b/src/main/java/com/xeiam/xchart/Chart.java @@ -52,6 +52,9 @@ public class Chart { height = pHeight; } + /** + * @param g + */ public void paint(final Graphics2D g) { // Sanity check @@ -121,7 +124,12 @@ public class Chart { */ public Series addSeries(String seriesName, Collection<Number> xData, Collection<Number> yData) { - return axisPair.addSeries(seriesName, xData, yData); + return axisPair.addSeries(seriesName, xData, yData, null); + } + + public Series addSeries(String seriesName, Collection<Number> xData, Collection<Number> yData, Collection<Number> errorBars) { + + return axisPair.addSeries(seriesName, xData, yData, errorBars); } /** @@ -132,6 +140,7 @@ public class Chart { * @param yData double[] * @return */ + @Deprecated public Series addSeries(String seriesName, double[] xData, double[] yData) { Collection<Number> xDataNumber = null; @@ -146,7 +155,7 @@ public class Chart { yDataNumber.add(new Double(d)); } - return axisPair.addSeries(seriesName, xDataNumber, yDataNumber); + return axisPair.addSeries(seriesName, xDataNumber, yDataNumber, null); } public void setChartTitle(String title) { diff --git a/src/main/java/com/xeiam/xchart/ChartColor.java b/src/main/java/com/xeiam/xchart/ChartColor.java index 45bc1b289a4a3b8f55413ba2ac403e53b831fcb6..5bfd7b8edaf7b946d266011641cc31ca6e44eca8 100644 --- a/src/main/java/com/xeiam/xchart/ChartColor.java +++ b/src/main/java/com/xeiam/xchart/ChartColor.java @@ -39,6 +39,12 @@ public enum ChartColor { Color color; + /** + * Get a AWT Color Object + * + * @param chartColor + * @return + */ protected static Color getAWTColor(ChartColor chartColor) { return chartColor.color; diff --git a/src/main/java/com/xeiam/xchart/Plot.java b/src/main/java/com/xeiam/xchart/Plot.java index 24a4e46ab2b1d59f7f492dfc88cd4c693b7926a4..b0908b9d2e55e9e1817889733167199d2abe3db9 100644 --- a/src/main/java/com/xeiam/xchart/Plot.java +++ b/src/main/java/com/xeiam/xchart/Plot.java @@ -20,7 +20,6 @@ import java.awt.Rectangle; import com.xeiam.xchart.interfaces.IChartPart; - /** * @author timmolter */ diff --git a/src/main/java/com/xeiam/xchart/PlotContent.java b/src/main/java/com/xeiam/xchart/PlotContent.java index 8e83f5c897e28ffee8c9b16804413a09ab41b216..12d12363ef0bd41ebedf1a269712a9f6f5e5b955 100644 --- a/src/main/java/com/xeiam/xchart/PlotContent.java +++ b/src/main/java/com/xeiam/xchart/PlotContent.java @@ -23,6 +23,7 @@ import java.util.Map; import com.xeiam.xchart.interfaces.IChartPart; import com.xeiam.xchart.series.Series; +import com.xeiam.xchart.series.SeriesLineStyle; /** * @author timmolter @@ -70,17 +71,25 @@ public class PlotContent implements IChartPart { Collection<Number> yData = series.getyData(); double yMin = chart.getAxisPair().getYAxis().getMin(); double yMax = chart.getAxisPair().getYAxis().getMax(); + Collection<Number> errorBars = series.getErrorBars(); int previousX = Integer.MIN_VALUE; int previousY = Integer.MIN_VALUE; Iterator<Number> xItr = xData.iterator(); Iterator<Number> yItr = yData.iterator(); + Iterator<Number> ebItr = null; + if (errorBars != null) { + ebItr = errorBars.iterator(); + } while (xItr.hasNext()) { double x = xItr.next().doubleValue(); double y = yItr.next().doubleValue(); - + double eb = 0.0; + if (errorBars != null) { + eb = ebItr.next().doubleValue(); + } if (!Double.isNaN(x) && !Double.isNaN(y)) { int xTransform = (int) (xLeftMargin + ((x - xMin) / (xMax - xMin) * xTickSpace)); @@ -115,6 +124,17 @@ public class PlotContent implements IChartPart { g.setColor(series.getMarkerColor()); series.getMarker().paint(g, xOffset, yOffset); } + + // paint errorbar + if (errorBars != null) { + g.setColor(ChartColor.getAWTColor(ChartColor.DARK_GREY)); + g.setStroke(SeriesLineStyle.getBasicStroke(SeriesLineStyle.SOLID)); + int bottom = (int) (-1 * bounds.getHeight() * eb / (yMax - yMin)); + int top = (int) (bounds.getHeight() * eb / (yMax - yMin)); + g.drawLine(xOffset, yOffset + bottom, xOffset, yOffset + top); + g.drawLine(xOffset - 3, yOffset + bottom, xOffset + 3, yOffset + bottom); + g.drawLine(xOffset - 3, yOffset + top, xOffset + 3, yOffset + top); + } } } } diff --git a/src/main/java/com/xeiam/xchart/series/Series.java b/src/main/java/com/xeiam/xchart/series/Series.java index 585f156133265946be8e853071d2c554d707c1d1..ac974c6b659ab6e6a4407a0b2000fe0a20e6c58e 100644 --- a/src/main/java/com/xeiam/xchart/series/Series.java +++ b/src/main/java/com/xeiam/xchart/series/Series.java @@ -18,6 +18,7 @@ package com.xeiam.xchart.series; import java.awt.BasicStroke; import java.awt.Color; import java.util.Collection; +import java.util.Iterator; import com.xeiam.xchart.series.markers.Marker; @@ -32,6 +33,8 @@ public class Series { protected Collection<Number> yData; + protected Collection<Number> errorBars; + /** the minimum value of axis range */ private double xMin; @@ -63,11 +66,12 @@ public class Series { * @param xData * @param yData */ - public Series(String name, Collection<Number> xData, Collection<Number> yData) { + public Series(String name, Collection<Number> xData, Collection<Number> yData, Collection<Number> errorBars) { this.name = name; this.xData = xData; this.yData = yData; + this.errorBars = errorBars; // xData double[] xMinMax = findMinMax(xData); @@ -75,7 +79,12 @@ public class Series { this.xMax = xMinMax[1]; // yData - double[] yMinMax = findMinMax(yData); + double[] yMinMax = null; + if (errorBars == null) { + yMinMax = findMinMax(yData); + } else { + yMinMax = findMinMaxWithErrorBars(yData, errorBars); + } this.yMin = yMinMax[0]; this.yMax = yMinMax[1]; // System.out.println(yMin); @@ -116,6 +125,37 @@ public class Series { return new double[] { min, max }; } + /** + * Finds the min and max of a dataset accounting for error bars + * + * @param data + * @return + */ + private double[] findMinMaxWithErrorBars(Collection<Number> data, Collection<Number> errorBars) { + + Double min = null; + Double max = null; + + Iterator<Number> itr = data.iterator(); + Iterator<Number> ebItr = errorBars.iterator(); + while (itr.hasNext()) { + double number = itr.next().doubleValue(); + double eb = ebItr.next().doubleValue(); + verify(number); + if (min == null || (number - eb) < min) { + if (!Double.isNaN(number)) { + min = number - eb; + } + } + if (max == null || (number + eb) > max) { + if (!Double.isNaN(number)) { + max = number + eb; + } + } + } + return new double[] { min, max }; + } + /** * Checks for invalid values in data array * @@ -145,6 +185,11 @@ public class Series { return yData; } + public Collection<Number> getErrorBars() { + + return errorBars; + } + public double getxMin() { return xMin; diff --git a/src/main/java/com/xeiam/xchart/series/SeriesLineStyle.java b/src/main/java/com/xeiam/xchart/series/SeriesLineStyle.java index b6bb2600c7354442129c590282d089cb43059e91..5193c6b9ab36b62479865c398b40c8fe8721800f 100644 --- a/src/main/java/com/xeiam/xchart/series/SeriesLineStyle.java +++ b/src/main/java/com/xeiam/xchart/series/SeriesLineStyle.java @@ -41,9 +41,23 @@ public enum SeriesLineStyle { DOT_DOT(3, new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 10.0f, new float[] { 1.0f, 1.0f }, 0.0f)); int id; + BasicStroke basicStroke; + private static int nextId = 0; + /** + * Constructor + * + * @param id + * @param color + */ + private SeriesLineStyle(int id, BasicStroke basicStroke) { + + this.id = id; + this.basicStroke = basicStroke; + } + private static final Map<Integer, SeriesLineStyle> idLookup = new HashMap<Integer, SeriesLineStyle>(); static { for (SeriesLineStyle seriesLineStyle : EnumSet.allOf(SeriesLineStyle.class)) { @@ -61,11 +75,22 @@ public enum SeriesLineStyle { nextId = 0; } - protected static BasicStroke getBasicStroke(SeriesLineStyle seriesMarker) { + /** + * Get an AWT Stroke + * + * @param seriesMarker + * @return + */ + public static BasicStroke getBasicStroke(SeriesLineStyle seriesMarker) { return seriesMarker.basicStroke; } + /** + * Gets the next Stroke + * + * @return + */ protected static BasicStroke getNextBasicStroke() { SeriesLineStyle seriesLineStyle = idLookup.get(nextId); @@ -76,15 +101,4 @@ public enum SeriesLineStyle { return idLookup.get(nextId++).basicStroke; } - /** - * Constructor - * - * @param id - * @param color - */ - private SeriesLineStyle(int id, BasicStroke basicStroke) { - - this.id = id; - this.basicStroke = basicStroke; - } } diff --git a/src/test/java/com/xeiam/xchart/example/Example8.java b/src/test/java/com/xeiam/xchart/example/Example8.java new file mode 100644 index 0000000000000000000000000000000000000000..7353d23ac1033075b0db79e8f84eaa14c3c682ee --- /dev/null +++ b/src/test/java/com/xeiam/xchart/example/Example8.java @@ -0,0 +1,66 @@ +/** + * Copyright 2011-2012 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.xchart.example; + +import java.util.ArrayList; +import java.util.Collection; + +import com.xeiam.xchart.Chart; +import com.xeiam.xchart.series.Series; +import com.xeiam.xchart.series.SeriesColor; +import com.xeiam.xchart.series.SeriesLineStyle; +import com.xeiam.xchart.series.SeriesMarker; +import com.xeiam.xchart.swing.SwingWrapper; + +/** + * Create a Chart with error bars + * + * @author timmolter + */ +public class Example8 { + + public static void main(String[] args) { + + // generates data + int size = 10; + Collection<Number> xData1 = new ArrayList<Number>(); + Collection<Number> yData1 = new ArrayList<Number>(); + Collection<Number> errorBars = new ArrayList<Number>(); + for (int i = 0; i <= size; i++) { + xData1.add(i); + yData1.add(10 * Math.exp(-i)); + errorBars.add(Math.random() + .3); + } + + // Create Chart + Chart chart = new Chart(440, 300); + + // Customize Chart + chart.setChartTitleVisible(false); + chart.setChartLegendVisible(false); + chart.setAxisTitlesVisible(false); + + // Series 1 + Series series1 = chart.addSeries("10^(-x)", xData1, yData1, errorBars); + series1.setLineColor(SeriesColor.PURPLE); + series1.setLineStyle(SeriesLineStyle.DASH_DASH); + series1.setMarkerColor(SeriesColor.GREEN); + series1.setMarker(SeriesMarker.SQUARE); + + new SwingWrapper(chart).displayChart(); + } + +}