diff --git a/xchart-demo/src/main/java/com/xeiam/xchart/demo/charts/bar/BarChart04.java b/xchart-demo/src/main/java/com/xeiam/xchart/demo/charts/bar/BarChart04.java index 74400142b1590d8c48cdcc6f3223735c26699d4b..5b51c274c0befe39cee1d9bbeaff7f606fc60cec 100644 --- a/xchart-demo/src/main/java/com/xeiam/xchart/demo/charts/bar/BarChart04.java +++ b/xchart-demo/src/main/java/com/xeiam/xchart/demo/charts/bar/BarChart04.java @@ -47,7 +47,7 @@ public class BarChart04 implements ExampleChart { // Create Chart Chart chart = new ChartBuilder().chartType(ChartType.Bar).width(800).height(600).title("XFactor vs. Age").xAxisTitle("Age").yAxisTitle("XFactor").build(); chart.addSeries("female", new double[] { 10, 20, 30, 40, 50 }, new double[] { 50, 10, 20, 40, 35 }); - chart.addSeries("male", new double[] { 10, 20, 30, 50 }, new double[] { 40, 30, 20, 60 }); + chart.addSeries("male", new double[] { 10, 20, 30, 40, 50 }, new double[] { 40, 30, 20, 0, 60 }); chart.getStyleManager().setYAxisMin(5); chart.getStyleManager().setYAxisMax(70); diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickBarChartCalculator.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickBarChartCalculator.java index 3bb37064e8bb3541cc23efcdd510e61a28352f60..4cac349127aea855ff64793041d25654807c0d70 100644 --- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickBarChartCalculator.java +++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickBarChartCalculator.java @@ -57,19 +57,30 @@ public class AxisTickBarChartCalculator extends AxisTickCalculator { // get all categories List<Object> categories = new ArrayList<Object>(); + + Series firstSeries = chartPainter.getAxisPair().getSeriesMap().values().iterator().next(); // we use this to check all series have the exact same length and values for (Series series : chartPainter.getAxisPair().getSeriesMap().values()) { + Iterator<?> firstSeriesItr = firstSeries.getXData().iterator(); Iterator<?> xItr = series.getXData().iterator(); while (xItr.hasNext()) { + + // check matching + Object next = xItr.next(); + Object firstSeriesNext = firstSeriesItr.next(); + if (!firstSeriesNext.equals(next)) { + throw new IllegalArgumentException("X-Axis data must exactly match all other Series X-Axis data for Bar Charts!!"); + } + Object x = null; if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.Number) { - x = xItr.next(); + x = next; } else if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.Date) { - x = (double) (((Date) xItr.next()).getTime()); + x = (double) (((Date) next).getTime()); } else if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.String) { - x = xItr.next(); + x = next; } if (!categories.contains(x)) { categories.add(x); @@ -134,7 +145,6 @@ public class AxisTickBarChartCalculator extends AxisTickCalculator { else if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.Date) { dateFormatter = new DateFormatter(chartPainter.getStyleManager()); } - int counter = 0; for (double tickPosition = firstPosition; tickPosition <= maxValue; tickPosition = tickPosition + gridStep) { @@ -147,7 +157,6 @@ public class AxisTickBarChartCalculator extends AxisTickCalculator { long timeUnit = dateFormatter.getTimeUnit(gridStepHint); tickLabels.add(dateFormatter.formatDate(tickPosition, timeUnit)); } - // int tickLabelPosition = (int) (margin + firstPosition + gridStep * counter++); double tickLabelPosition = margin + ((tickPosition - minValue) / (maxValue - minValue) * tickSpace); tickLocations.add(tickLabelPosition); } 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 18e016664dbb2fc37145691e64c4021c837398e8..17e6ca015010bd5a2b4fa5936e2c017902f84404 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 @@ -18,10 +18,8 @@ package com.xeiam.xchart.internal.chartpart; import java.awt.Graphics2D; import java.awt.geom.Path2D; import java.awt.geom.Rectangle2D; -import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; -import java.util.List; import com.xeiam.xchart.Series; import com.xeiam.xchart.StyleManager; @@ -56,19 +54,7 @@ public class PlotContentBarChart extends PlotContent { double yTickSpace = styleManager.getAxisTickSpaceRatio() * bounds.getHeight(); double yTopMargin = Utils.getTickStartOffset(bounds.getHeight(), yTickSpace); - // get all categories - List<Object> categories = new ArrayList<Object>(); - for (Series series : getChartPainter().getAxisPair().getSeriesMap().values()) { - - Iterator<?> xItr = series.getXData().iterator(); - while (xItr.hasNext()) { - Object object = xItr.next(); - if (!categories.contains(object)) { - categories.add(object); - } - } - } - int numBars = categories.size(); + int numBars = getChartPainter().getAxisPair().getSeriesMap().values().iterator().next().getXData().size(); double gridStep = xTickSpace / numBars; // plot series @@ -122,70 +108,78 @@ public class PlotContentBarChart extends PlotContent { // System.out.println(yMin); // System.out.println(yMax); - Iterator<?> categoryItr = categories.iterator(); + // all the x-axis data are guaranteed to be the same so we just use the first one Iterator<? extends Number> yItr = yData.iterator(); int barCounter = 0; - while (categoryItr.hasNext()) { + while (yItr.hasNext()) { + + double y = ((Number) yItr.next()).doubleValue(); + if (getChartPainter().getStyleManager().isYAxisLogarithmic()) { + y = Math.log10(y); + } - if (xData.contains(categoryItr.next())) { + double yTop = 0.0; + double yBottom = 0.0; - double y = ((Number) yItr.next()).doubleValue(); - if (getChartPainter().getStyleManager().isYAxisLogarithmic()) { - y = Math.log10(y); + switch (chartForm) { + case 1: // positive chart + + // check for points off the chart draw area due to a custom yMin + if (y < yMin) { + barCounter++; + continue; } - double yTop = 0.0; - double yBottom = 0.0; + yTop = y; + yBottom = yMin; + break; + case -1: // negative chart + + // check for points off the chart draw area due to a custom yMin + if (y > yMax) { + barCounter++; + continue; + } - switch (chartForm) { - case 1: // positive chart + yTop = yMax; + yBottom = y; + break; + case 0: // span chart + if (y >= 0.0) { // positive yTop = y; - yBottom = yMin; - break; - case -1: // negative chart - yTop = yMax; + yBottom = 0.0; + } + else { + yTop = 0.0; yBottom = y; - break; - case 0: // span chart - if (y >= 0.0) { // positive - yTop = y; - yBottom = 0.0; - } - else { - yTop = 0.0; - yBottom = y; - } - break; - default: - break; } + break; + default: + break; + } - double yTransform = bounds.getHeight() - (yTopMargin + (yTop - yMin) / (yMax - yMin) * yTickSpace); + double yTransform = bounds.getHeight() - (yTopMargin + (yTop - yMin) / (yMax - yMin) * yTickSpace); - double yOffset = bounds.getY() + yTransform; + double yOffset = bounds.getY() + yTransform; - double zeroTransform = bounds.getHeight() - (yTopMargin + (yBottom - yMin) / (yMax - yMin) * yTickSpace); - double zeroOffset = bounds.getY() + zeroTransform; + double zeroTransform = bounds.getHeight() - (yTopMargin + (yBottom - yMin) / (yMax - yMin) * yTickSpace); + double zeroOffset = bounds.getY() + zeroTransform; - // paint bar - double barWidth = gridStep / getChartPainter().getAxisPair().getSeriesMap().size() / 1.1; - double barMargin = gridStep * .05; - double xOffset = bounds.getX() + xLeftMargin + gridStep * barCounter++ + seriesCounter * barWidth + barMargin; - g.setColor(series.getStrokeColor()); + // paint bar + double barWidth = gridStep / getChartPainter().getAxisPair().getSeriesMap().size() / 1.1; + double barMargin = gridStep * .05; + double xOffset = bounds.getX() + xLeftMargin + gridStep * barCounter++ + seriesCounter * barWidth + barMargin; + g.setColor(series.getStrokeColor()); - Path2D.Double path = new Path2D.Double(); - path.moveTo(xOffset, yOffset); - path.lineTo(xOffset + barWidth, yOffset); - path.lineTo(xOffset + barWidth, zeroOffset); - path.lineTo(xOffset, zeroOffset); - path.closePath(); - g.fill(path); + Path2D.Double path = new Path2D.Double(); + path.moveTo(xOffset, yOffset); + path.lineTo(xOffset + barWidth, yOffset); + path.lineTo(xOffset + barWidth, zeroOffset); + path.lineTo(xOffset, zeroOffset); + path.closePath(); + g.fill(path); - } - else { - barCounter++; - } } seriesCounter++; } diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/PlotSurface.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/PlotSurface.java index e99c1fa3432bd0c29b8592fa27701e573b0c93b1..5580d85bc1e92315a9276d4aa5901fd90e7a138a 100644 --- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/PlotSurface.java +++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/PlotSurface.java @@ -95,7 +95,12 @@ public class PlotSurface implements ChartPart { // vertical if (getChartPainter().getStyleManager().getChartType() != ChartType.Bar - && (getChartPainter().getStyleManager().isPlotGridLinesVisible() || getChartPainter().getStyleManager().isPlotTicksMarksVisible())) { + + && (getChartPainter().getStyleManager().isPlotGridLinesVisible() + + || getChartPainter().getStyleManager().isPlotTicksMarksVisible()) + + ) { List<Double> xAxisTickLocations = getChartPainter().getAxisPair().getXAxis().getAxisTick().getTickLocations(); for (int i = 0; i < xAxisTickLocations.size(); i++) {