From dad6a50182ecae1ced53931860b80c2c300ab717 Mon Sep 17 00:00:00 2001
From: Tim Molter <tim.molter@gmail.com>
Date: Sat, 20 Dec 2014 13:22:35 +0100
Subject: [PATCH] issue #88 Added error bars to bar charts

---
 .../com/xeiam/xchart/demo/XChartDemo.java     |  4 +
 .../xchart/demo/charts/bar/BarChart08.java    | 83 +++++++++++++++++++
 .../chartpart/PlotContentBarChart.java        | 42 ++++++++++
 .../chartpart/PlotContentLineChart.java       | 15 ++--
 .../xchart/internal/style/XChartTheme.java    |  2 +-
 5 files changed, 136 insertions(+), 10 deletions(-)
 create mode 100644 xchart-demo/src/main/java/com/xeiam/xchart/demo/charts/bar/BarChart08.java

diff --git a/xchart-demo/src/main/java/com/xeiam/xchart/demo/XChartDemo.java b/xchart-demo/src/main/java/com/xeiam/xchart/demo/XChartDemo.java
index 25e914d8..4045fb62 100644
--- a/xchart-demo/src/main/java/com/xeiam/xchart/demo/XChartDemo.java
+++ b/xchart-demo/src/main/java/com/xeiam/xchart/demo/XChartDemo.java
@@ -41,6 +41,7 @@ import com.xeiam.xchart.demo.charts.bar.BarChart04;
 import com.xeiam.xchart.demo.charts.bar.BarChart05;
 import com.xeiam.xchart.demo.charts.bar.BarChart06;
 import com.xeiam.xchart.demo.charts.bar.BarChart07;
+import com.xeiam.xchart.demo.charts.bar.BarChart08;
 import com.xeiam.xchart.demo.charts.date.DateChart01;
 import com.xeiam.xchart.demo.charts.date.DateChart02;
 import com.xeiam.xchart.demo.charts.date.DateChart03;
@@ -261,6 +262,9 @@ public class XChartDemo extends JPanel implements TreeSelectionListener {
     defaultMutableTreeNode = new DefaultMutableTreeNode(new ChartInfo("BarChart07 - Histogram Not Overlapped", new BarChart07().getChart()));
     category.add(defaultMutableTreeNode);
 
+    defaultMutableTreeNode = new DefaultMutableTreeNode(new ChartInfo("BarChart08 - Histogram with Error Bars", new BarChart08().getChart()));
+    category.add(defaultMutableTreeNode);
+
     // Theme category
     category = new DefaultMutableTreeNode("Chart Themes");
     top.add(category);
diff --git a/xchart-demo/src/main/java/com/xeiam/xchart/demo/charts/bar/BarChart08.java b/xchart-demo/src/main/java/com/xeiam/xchart/demo/charts/bar/BarChart08.java
new file mode 100644
index 00000000..a2d717ae
--- /dev/null
+++ b/xchart-demo/src/main/java/com/xeiam/xchart/demo/charts/bar/BarChart08.java
@@ -0,0 +1,83 @@
+/**
+ * Copyright 2011 - 2014 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.demo.charts.bar;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import com.xeiam.xchart.Chart;
+import com.xeiam.xchart.ChartBuilder;
+import com.xeiam.xchart.Histogram;
+import com.xeiam.xchart.StyleManager.ChartType;
+import com.xeiam.xchart.StyleManager.LegendPosition;
+import com.xeiam.xchart.SwingWrapper;
+import com.xeiam.xchart.demo.charts.ExampleChart;
+
+/**
+ * Histogram with Error Bars
+ * <p>
+ * Demonstrates the following:
+ * <ul>
+ * <li>Histogram
+ * <li>Bar Chart with error bars
+ */
+public class BarChart08 implements ExampleChart {
+
+  public static void main(String[] args) {
+
+    ExampleChart exampleChart = new BarChart08();
+    Chart chart = exampleChart.getChart();
+    new SwingWrapper(chart).displayChart();
+  }
+
+  @Override
+  public Chart getChart() {
+
+    // Create Chart
+    Chart chart = new ChartBuilder().chartType(ChartType.Bar).width(800).height(600).title("Histogram").xAxisTitle("Mean").yAxisTitle("Count").build();
+
+    Histogram histogram1 = new Histogram(getGaussianData(10000), 10, -10, 10);
+    chart.addSeries("histogram", histogram1.getxAxisData(), histogram1.getyAxisData(), getFakeErrorData(histogram1.getxAxisData().size()));
+
+    // Customize Chart
+    chart.getStyleManager().setLegendPosition(LegendPosition.InsideNW);
+    chart.getStyleManager().setBarWidthPercentage(.96);
+
+    return chart;
+  }
+
+  private List<Double> getGaussianData(int count) {
+
+    List<Double> data = new ArrayList<Double>(count);
+    Random r = new Random();
+    for (int i = 0; i < count; i++) {
+      data.add(r.nextGaussian() * 5);
+      // data.add(r.nextDouble() * 60 - 30);
+    }
+    return data;
+  }
+
+  private List<Double> getFakeErrorData(int count) {
+
+    List<Double> data = new ArrayList<Double>(count);
+    Random r = new Random();
+    for (int i = 0; i < count; i++) {
+      data.add(r.nextDouble() * 200);
+    }
+    return data;
+  }
+}
diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/PlotContentBarChart.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/PlotContentBarChart.java
index 6ee673bd..7b497463 100644
--- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/PlotContentBarChart.java
+++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/PlotContentBarChart.java
@@ -17,6 +17,8 @@ package com.xeiam.xchart.internal.chartpart;
 
 import java.awt.Graphics2D;
 import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.geom.Line2D;
 import java.awt.geom.Path2D;
 import java.awt.geom.Rectangle2D;
 import java.util.Collection;
@@ -122,6 +124,11 @@ public class PlotContentBarChart extends PlotContent {
 
       // all the x-axis data are guaranteed to be the same so we just use the first one
       Iterator<? extends Number> yItr = yData.iterator();
+      Iterator<? extends Number> ebItr = null;
+      Collection<? extends Number> errorBars = series.getErrorBars();
+      if (errorBars != null) {
+        ebItr = errorBars.iterator();
+      }
 
       int barCounter = 0;
       while (yItr.hasNext()) {
@@ -210,6 +217,41 @@ public class PlotContentBarChart extends PlotContent {
           g.draw(path);
         }
 
+        // paint errorbars
+
+        if (errorBars != null) {
+
+          double eb = ebItr.next().doubleValue();
+
+          // set error bar style
+          if (getChartPainter().getStyleManager().isErrorBarsColorSeriesColor()) {
+            g.setColor(series.getStrokeColor());
+          }
+          else {
+            g.setColor(getChartPainter().getStyleManager().getErrorBarsColor());
+          }
+          g.setStroke(errorBarStroke);
+
+          // Top value
+          double topValue = y + eb;
+          double topEBTransform = bounds.getHeight() - (yTopMargin + (topValue - yMin) / (yMax - yMin) * yTickSpace);
+          double topEBOffset = bounds.getY() + topEBTransform;
+
+          // Bottom value
+          double bottomValue = y - eb;
+          double bottomEBTransform = bounds.getHeight() - (yTopMargin + (bottomValue - yMin) / (yMax - yMin) * yTickSpace);
+          double bottomEBOffset = bounds.getY() + bottomEBTransform;
+
+          // Draw it
+          double errorBarOffset = xOffset + barWidth / 2;
+          Shape line = new Line2D.Double(errorBarOffset, topEBOffset, errorBarOffset, bottomEBOffset);
+          g.draw(line);
+          line = new Line2D.Double(errorBarOffset - 3, bottomEBOffset, errorBarOffset + 3, bottomEBOffset);
+          g.draw(line);
+          line = new Line2D.Double(errorBarOffset - 3, topEBOffset, errorBarOffset + 3, topEBOffset);
+          g.draw(line);
+        }
+
       }
       seriesCounter++;
     }
diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/PlotContentLineChart.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/PlotContentLineChart.java
index bcf987e8..ec65b7de 100644
--- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/PlotContentLineChart.java
+++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/PlotContentLineChart.java
@@ -114,7 +114,6 @@ public class PlotContentLineChart extends PlotContent {
         yMin = Math.log10(yMin);
         yMax = Math.log10(yMax);
       }
-      Collection<? extends Number> errorBars = series.getErrorBars();
 
       double previousX = Integer.MIN_VALUE;
       double previousY = Integer.MIN_VALUE;
@@ -122,6 +121,7 @@ public class PlotContentLineChart extends PlotContent {
       Iterator<?> xItr = xData.iterator();
       Iterator<? extends Number> yItr = yData.iterator();
       Iterator<? extends Number> ebItr = null;
+      Collection<? extends Number> errorBars = series.getErrorBars();
       if (errorBars != null) {
         ebItr = errorBars.iterator();
       }
@@ -227,17 +227,11 @@ public class PlotContentLineChart extends PlotContent {
         }
 
         // paint errorbars
-
-        double eb = 0.0;
-
-        if (errorBars != null) {
-          eb = ebItr.next().doubleValue();
-        }
-
         if (errorBars != null) {
 
-          // set error bar color
+          double eb = ebItr.next().doubleValue();
 
+          // set error bar style
           if (getChartPainter().getStyleManager().isErrorBarsColorSeriesColor()) {
             g.setColor(series.getStrokeColor());
           }
@@ -246,6 +240,7 @@ public class PlotContentLineChart extends PlotContent {
           }
           g.setStroke(errorBarStroke);
 
+          // Top value
           double topValue = 0.0;
           if (getChartPainter().getStyleManager().isYAxisLogarithmic()) {
             topValue = yOrig + eb;
@@ -257,6 +252,7 @@ public class PlotContentLineChart extends PlotContent {
           double topEBTransform = bounds.getHeight() - (yTopMargin + (topValue - yMin) / (yMax - yMin) * yTickSpace);
           double topEBOffset = bounds.getY() + topEBTransform;
 
+          // Bottom value
           double bottomValue = 0.0;
           if (getChartPainter().getStyleManager().isYAxisLogarithmic()) {
             bottomValue = yOrig - eb;
@@ -269,6 +265,7 @@ public class PlotContentLineChart extends PlotContent {
           double bottomEBTransform = bounds.getHeight() - (yTopMargin + (bottomValue - yMin) / (yMax - yMin) * yTickSpace);
           double bottomEBOffset = bounds.getY() + bottomEBTransform;
 
+          // Draw it
           Shape line = new Line2D.Double(xOffset, topEBOffset, xOffset, bottomEBOffset);
           g.draw(line);
           line = new Line2D.Double(xOffset - 3, bottomEBOffset, xOffset + 3, bottomEBOffset);
diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/style/XChartTheme.java b/xchart/src/main/java/com/xeiam/xchart/internal/style/XChartTheme.java
index d09084da..b03db2b0 100644
--- a/xchart/src/main/java/com/xeiam/xchart/internal/style/XChartTheme.java
+++ b/xchart/src/main/java/com/xeiam/xchart/internal/style/XChartTheme.java
@@ -312,7 +312,7 @@ public class XChartTheme implements Theme {
   @Override
   public Color getErrorBarsColor() {
 
-    return ChartColor.getAWTColor(ChartColor.DARK_GREY);
+    return ChartColor.getAWTColor(ChartColor.BLACK);
   }
 
   @Override
-- 
GitLab