diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTick.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTick.java index c21536f5767fdcdbdcb1b2dbf31104bb409470e7..86689299279bd6b3cf8cd0d924a43799d7d177f6 100644 --- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTick.java +++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTick.java @@ -152,7 +152,7 @@ public class AxisTick implements ChartPart { return axisTickLabels; } - public List<Integer> getTickLocations() { + public List<Double> getTickLocations() { return gridStep.getTickLocations(); } 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 78bc5e9f678d9dce75184bcdd0e39a72ba2fc3d1..33e780d0a2ce34ad25390a6d6dd5abc9749b61fe 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 @@ -77,38 +77,81 @@ public class AxisTickBarChartCalculator extends AxisTickCalculator { } } - int numCategories = categories.size(); + if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.String) { - double gridStep = (tickSpace / (double) numCategories); - // int firstPosition = (int) (gridStep / 2.0); - double firstPosition = getFirstPosition(gridStep); + double gridStep = (tickSpace / (double) categories.size()); + double firstPosition = gridStep / 2.0; + int counter = 0; + for (Object category : categories) { + tickLabels.add(category.toString()); + double tickLabelPosition = margin + firstPosition + gridStep * counter++; + tickLocations.add(tickLabelPosition); + } + } + else if (categories.size() < 13) { // Number or Date and 12 or less categories - // generate all tickLabels and tickLocations from the first to last position - NumberFormatter numberFormatter = null; - DateFormatter dateFormatter = null; + double gridStep = (tickSpace / (double) categories.size()); + double firstPosition = gridStep / 2.0; - if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.Number) { - numberFormatter = new NumberFormatter(styleManager); - } - else if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.Date) { - dateFormatter = new DateFormatter(chartPainter.getStyleManager()); + // generate all tickLabels and tickLocations from the first to last position + NumberFormatter numberFormatter = null; + DateFormatter dateFormatter = null; + + if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.Number) { + numberFormatter = new NumberFormatter(styleManager); + } + else if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.Date) { + dateFormatter = new DateFormatter(chartPainter.getStyleManager()); + } + int counter = 0; + + for (Object category : categories) { + if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.Number) { + tickLabels.add(numberFormatter.formatNumber((Double) category)); + } + else if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.Date) { + long span = (long) Math.abs(maxValue - minValue); // in data space + long gridStepHint = (long) (span / (double) tickSpace * styleManager.getXAxisTickMarkSpacingHint()); + long timeUnit = dateFormatter.getTimeUnit(gridStepHint); + tickLabels.add(dateFormatter.formatDate((Double) category, timeUnit)); + } + double tickLabelPosition = (int) (margin + firstPosition + gridStep * counter++); + tickLocations.add(tickLabelPosition); + } } - int counter = 0; - for (Object category : categories) { + else { // Number or Date + + double gridStep = getNumericalGridStep(tickSpace); + double firstPosition = getFirstPosition(gridStep); + + // generate all tickLabels and tickLocations from the first to last position + NumberFormatter numberFormatter = null; + DateFormatter dateFormatter = null; + if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.Number) { - tickLabels.add(numberFormatter.formatNumber((Double) category)); + numberFormatter = new NumberFormatter(styleManager); } else if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.Date) { - long span = (long) Math.abs(maxValue - minValue); // in data space - long gridStepHint = (long) (span / (double) tickSpace * styleManager.getXAxisTickMarkSpacingHint()); - long timeUnit = dateFormatter.getTimeUnit(gridStepHint); - tickLabels.add(dateFormatter.formatDate((Double) category, timeUnit)); + dateFormatter = new DateFormatter(chartPainter.getStyleManager()); } - else if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.String) { - tickLabels.add(category.toString()); + int counter = 0; + + for (double tickPosition = firstPosition; tickPosition <= maxValue; tickPosition = tickPosition + gridStep) { + + if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.Number) { + tickLabels.add(numberFormatter.formatNumber(tickPosition)); + } + else if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.Date) { + long span = (long) Math.abs(maxValue - minValue); // in data space + long gridStepHint = (long) (span / (double) tickSpace * styleManager.getXAxisTickMarkSpacingHint()); + 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); } - int tickLabelPosition = (int) (margin + firstPosition + gridStep * counter++); - tickLocations.add(tickLabelPosition); } + } } diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickCalculator.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickCalculator.java index 02ea5497f0fddf89b7f75ddeb5186cf3604d34c2..fd93cccb3a563004c63250d8c7c341fdc142c50d 100644 --- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickCalculator.java +++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickCalculator.java @@ -29,7 +29,7 @@ import com.xeiam.xchart.internal.chartpart.Axis.Direction; public abstract class AxisTickCalculator { /** the List of tick label position in pixels */ - protected List<Integer> tickLocations = new LinkedList<Integer>();; + protected List<Double> tickLocations = new LinkedList<Double>();; /** the List of tick label values */ protected List<String> tickLabels = new LinkedList<String>(); @@ -110,7 +110,7 @@ public abstract class AxisTickCalculator { return firstPosition; } - public List<Integer> getTickLocations() { + public List<Double> getTickLocations() { return tickLocations; } @@ -120,4 +120,70 @@ public abstract class AxisTickCalculator { return tickLabels; } + /** + * Determine the grid step for the data set given the space in pixels allocated for the axis + * + * @param tickSpace in plot space + * @return + */ + public double getNumericalGridStep(int tickSpace) { + + // this prevents an infinite loop when the plot gets sized really small. + if (tickSpace < 10) { + return 1.0; + } + + // the span of the data + double span = Math.abs(maxValue - minValue); // in data space + + int tickMarkSpaceHint = (axisDirection == Direction.X ? styleManager.getXAxisTickMarkSpacingHint() : styleManager.getYAxisTickMarkSpacingHint()); + + // for very short plots, squeeze some more ticks in than normal + if (axisDirection == Direction.Y && tickSpace < 160) { + tickMarkSpaceHint = 25; + } + + double gridStepHint = span / tickSpace * tickMarkSpaceHint; + + // gridStepHint --> significand * 10 ** exponent + // e.g. 724.1 --> 7.241 * 10 ** 2 + double significand = gridStepHint; + int exponent = 0; + if (significand == 0) { + exponent = 1; + } + else if (significand < 1) { + while (significand < 1) { + significand *= 10.0; + exponent--; + } + } + else { + while (significand >= 10 || significand == Double.NEGATIVE_INFINITY) { + significand /= 10.0; + exponent++; + } + } + + // calculate the grid step with hint. + double gridStep; + if (significand > 7.5) { + // gridStep = 10.0 * 10 ** exponent + gridStep = 10.0 * Utils.pow(10, exponent); + } + else if (significand > 3.5) { + // gridStep = 5.0 * 10 ** exponent + gridStep = 5.0 * Utils.pow(10, exponent); + } + else if (significand > 1.5) { + // gridStep = 2.0 * 10 ** exponent + gridStep = 2.0 * Utils.pow(10, exponent); + } + else { + // gridStep = 1.0 * 10 ** exponent + gridStep = Utils.pow(10, exponent); + } + return gridStep; + } + } diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickDateCalculator.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickDateCalculator.java index 512b15e23d60cc3ba8ba6816070840b852c3c099..26094572422047a6af92935fa47fe20cfeebf16c 100644 --- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickDateCalculator.java +++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickDateCalculator.java @@ -47,7 +47,7 @@ public class AxisTickDateCalculator extends AxisTickCalculator { private void calculate() { // tick space - a percentage of the working space available for ticks - int tickSpace = (int)(styleManager.getAxisTickSpaceRatio() * workingSpace); // in plot space + int tickSpace = (int) (styleManager.getAxisTickSpaceRatio() * workingSpace); // in plot space // where the tick should begin in the working space in pixels int margin = Utils.getTickStartOffset(workingSpace, tickSpace); // in plot space double gridStep = getGridStepForDecimal(tickSpace); @@ -74,7 +74,7 @@ public class AxisTickDateCalculator extends AxisTickCalculator { tickLabels.add(dateFormatter.formatDate(tickPosition, timeUnit)); // here we convert tickPosition finally to plot space, i.e. pixels - int tickLabelPosition = (int) (margin + ((tickPosition - minValue) / (maxValue - minValue) * tickSpace)); + double tickLabelPosition = (int) (margin + ((tickPosition - minValue) / (maxValue - minValue) * tickSpace)); tickLocations.add(tickLabelPosition); } } diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickLabels.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickLabels.java index 6beba45d9c363b35177410f7468db6a116237f75..5b851847dfb8c08cf7b00acd8859f67e49441d9b 100644 --- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickLabels.java +++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickLabels.java @@ -63,7 +63,7 @@ public class AxisTickLabels implements ChartPart { String tickLabel = axisTick.getTickLabels().get(i); // System.out.println(tickLabel); - int tickLocation = axisTick.getTickLocations().get(i); + double tickLocation = axisTick.getTickLocations().get(i); if (tickLabel != null) { // some are null for logarithmic axes @@ -100,7 +100,7 @@ public class AxisTickLabels implements ChartPart { for (int i = 0; i < axisTick.getTickLabels().size(); i++) { String tickLabel = axisTick.getTickLabels().get(i); - int tickLocation = axisTick.getTickLocations().get(i); + double tickLocation = axisTick.getTickLocations().get(i); if (tickLabel != null) { // some are null for logarithmic axes FontRenderContext frc = g.getFontRenderContext(); diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickLogarithmicCalculator.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickLogarithmicCalculator.java index db3f0cbe9a31d15ec90d65c790681fa3882a62d9..fdc53cfc6963bcdeff318c7440096c2e8e179024 100644 --- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickLogarithmicCalculator.java +++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickLogarithmicCalculator.java @@ -49,7 +49,7 @@ public class AxisTickLogarithmicCalculator extends AxisTickCalculator { // a check if all axis data are the exact same values if (minValue == maxValue) { tickLabels.add(numberFormatter.formatNumber(maxValue)); - tickLocations.add((int) (workingSpace / 2.0)); + tickLocations.add(workingSpace / 2.0); return; } @@ -117,7 +117,7 @@ public class AxisTickLogarithmicCalculator extends AxisTickCalculator { } // add all the tick marks though - int tickLabelPosition = (int) (margin + (Math.log10(j) - Math.log10(minValue)) / (Math.log10(maxValue) - Math.log10(minValue)) * tickSpace); + double tickLabelPosition = (int) (margin + (Math.log10(j) - Math.log10(minValue)) / (Math.log10(maxValue) - Math.log10(minValue)) * tickSpace); tickLocations.add(tickLabelPosition); } tickStep = tickStep * Utils.pow(10, 1); diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickMarks.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickMarks.java index 5d81030072dc9fb5029e0c1c6d01b63a5b2a113b..9dc312310dfbc8aebc6b3cec8e6d9874d1b33a18 100644 --- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickMarks.java +++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickMarks.java @@ -63,7 +63,7 @@ public class AxisTickMarks implements ChartPart { for (int i = 0; i < axisTick.getTickLabels().size(); i++) { - int tickLocation = axisTick.getTickLocations().get(i); + double tickLocation = axisTick.getTickLocations().get(i); Shape line = new Line2D.Double(xOffset, yOffset + axisTick.getAxis().getPaintZone().getHeight() - tickLocation, xOffset + getChartPainter().getStyleManager().getAxisTickMarkLength(), yOffset @@ -98,7 +98,7 @@ public class AxisTickMarks implements ChartPart { for (int i = 0; i < axisTick.getTickLabels().size(); i++) { - int tickLocation = axisTick.getTickLocations().get(i); + double tickLocation = axisTick.getTickLocations().get(i); Shape line = new Line2D.Double(xOffset + tickLocation, yOffset, xOffset + tickLocation, yOffset - getChartPainter().getStyleManager().getAxisTickMarkLength()); g.draw(line); diff --git a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickNumericalCalculator.java b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickNumericalCalculator.java index 85e296b640fdafd7f2014994818393e543f48ae4..8b18830ca7656e4b0fba9636c3fac7d39f5295d3 100644 --- a/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickNumericalCalculator.java +++ b/xchart/src/main/java/com/xeiam/xchart/internal/chartpart/AxisTickNumericalCalculator.java @@ -49,17 +49,17 @@ public class AxisTickNumericalCalculator extends AxisTickCalculator { // a check if all axis data are the exact same values if (minValue == maxValue) { tickLabels.add(numberFormatter.formatNumber(maxValue)); - tickLocations.add((int) (workingSpace / 2.0)); + tickLocations.add(workingSpace / 2.0); return; } // tick space - a percentage of the working space available for ticks - int tickSpace = (int)(styleManager.getAxisTickSpaceRatio() * workingSpace); // in plot space + int tickSpace = (int) (styleManager.getAxisTickSpaceRatio() * workingSpace); // in plot space // where the tick should begin in the working space in pixels int margin = Utils.getTickStartOffset(workingSpace, tickSpace); // in plot space double gridStep = getGridStepForDecimal(tickSpace); - double gridStep = getGridStep(tickSpace); + double gridStep = getNumericalGridStep(tickSpace); double firstPosition = getFirstPosition(gridStep); // generate all tickLabels and tickLocations from the first to last position @@ -67,74 +67,9 @@ public class AxisTickNumericalCalculator extends AxisTickCalculator { tickLabels.add(numberFormatter.formatNumber(tickPosition)); // here we convert tickPosition finally to plot space, i.e. pixels - int tickLabelPosition = (int) (margin + ((tickPosition - minValue) / (maxValue - minValue) * tickSpace)); + double tickLabelPosition = margin + ((tickPosition - minValue) / (maxValue - minValue) * tickSpace); tickLocations.add(tickLabelPosition); } } - /** - * Determine the grid step for the data set given the space in pixels allocated for the axis - * - * @param tickSpace in plot space - * @return - */ - private double getGridStep(int tickSpace) { - - // this prevents an infinite loop when the plot gets sized really small. - if (tickSpace < 10) { - return 1.0; - } - - // the span of the data - double span = Math.abs(maxValue - minValue); // in data space - - int tickMarkSpaceHint = (axisDirection == Direction.X ? styleManager.getXAxisTickMarkSpacingHint() : styleManager.getYAxisTickMarkSpacingHint()); - - // for very short plots, squeeze some more ticks in than normal - if (axisDirection == Direction.Y && tickSpace < 160) { - tickMarkSpaceHint = 25; - } - - double gridStepHint = span / tickSpace * tickMarkSpaceHint; - - // gridStepHint --> significand * 10 ** exponent - // e.g. 724.1 --> 7.241 * 10 ** 2 - double significand = gridStepHint; - int exponent = 0; - if (significand == 0) { - exponent = 1; - } - else if (significand < 1) { - while (significand < 1) { - significand *= 10.0; - exponent--; - } - } - else { - while (significand >= 10 || significand == Double.NEGATIVE_INFINITY) { - significand /= 10.0; - exponent++; - } - } - - // calculate the grid step with hint. - double gridStep; - if (significand > 7.5) { - // gridStep = 10.0 * 10 ** exponent - gridStep = 10.0 * Utils.pow(10, exponent); - } - else if (significand > 3.5) { - // gridStep = 5.0 * 10 ** exponent - gridStep = 5.0 * Utils.pow(10, exponent); - } - else if (significand > 1.5) { - // gridStep = 2.0 * 10 ** exponent - gridStep = 2.0 * Utils.pow(10, exponent); - } - else { - // gridStep = 1.0 * 10 ** exponent - gridStep = Utils.pow(10, exponent); - } - return gridStep; - } } 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 ed57666dff6b43f8337ce209b9126ebd637c9af7..e99c1fa3432bd0c29b8592fa27701e573b0c93b1 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 @@ -67,7 +67,7 @@ public class PlotSurface implements ChartPart { if (getChartPainter().getStyleManager().isPlotGridLinesVisible() || getChartPainter().getStyleManager().isPlotTicksMarksVisible()) { // horizontal - List<Integer> yAxisTickLocations = getChartPainter().getAxisPair().getYAxis().getAxisTick().getTickLocations(); + List<Double> yAxisTickLocations = getChartPainter().getAxisPair().getYAxis().getAxisTick().getTickLocations(); for (int i = 0; i < yAxisTickLocations.size(); i++) { double tickLocation = yAxisTickLocations.get(i); @@ -97,7 +97,7 @@ public class PlotSurface implements ChartPart { if (getChartPainter().getStyleManager().getChartType() != ChartType.Bar && (getChartPainter().getStyleManager().isPlotGridLinesVisible() || getChartPainter().getStyleManager().isPlotTicksMarksVisible())) { - List<Integer> xAxisTickLocations = getChartPainter().getAxisPair().getXAxis().getAxisTick().getTickLocations(); + List<Double> xAxisTickLocations = getChartPainter().getAxisPair().getXAxis().getAxisTick().getTickLocations(); for (int i = 0; i < xAxisTickLocations.size(); i++) { double tickLocation = xAxisTickLocations.get(i); diff --git a/xchart/src/test/java/com/xeiam/xchart/DateAxisTickCalculatorTest.java b/xchart/src/test/java/com/xeiam/xchart/DateAxisTickCalculatorTest.java index 2c754beed7c56ffdc3115f3ddb70bf389a5a2768..051495ddeb63e2196ab2b5f512decb56da7df344 100644 --- a/xchart/src/test/java/com/xeiam/xchart/DateAxisTickCalculatorTest.java +++ b/xchart/src/test/java/com/xeiam/xchart/DateAxisTickCalculatorTest.java @@ -41,9 +41,9 @@ public class DateAxisTickCalculatorTest { assertThat(tickLabels.size(), equalTo(6)); assertThat(tickLabels.get(0), equalTo("17:50")); - List<Integer> tickLocations = decimalAxisTickCalculator.getTickLocations(); + List<Double> tickLocations = decimalAxisTickCalculator.getTickLocations(); System.out.println(Arrays.toString(tickLocations.toArray())); assertThat(tickLocations.size(), equalTo(6)); - assertThat(tickLocations.get(0), equalTo(100)); + assertThat(tickLocations.get(0), equalTo(100.0)); } } diff --git a/xchart/src/test/java/com/xeiam/xchart/DecimalAxisTickCalculatorTest.java b/xchart/src/test/java/com/xeiam/xchart/DecimalAxisTickCalculatorTest.java index ae145783141b9ed9141f6d235a4042a35ea9ca4a..e616b9e7cd0ce81cc99e9c1de8948d45cd7448d9 100644 --- a/xchart/src/test/java/com/xeiam/xchart/DecimalAxisTickCalculatorTest.java +++ b/xchart/src/test/java/com/xeiam/xchart/DecimalAxisTickCalculatorTest.java @@ -41,9 +41,9 @@ public class DecimalAxisTickCalculatorTest { assertThat(tickLabels.size(), equalTo(7)); assertThat(tickLabels.get(0), equalTo("-15")); - List<Integer> tickLocations = decimalAxisTickCalculator.getTickLocations(); + List<Double> tickLocations = decimalAxisTickCalculator.getTickLocations(); System.out.println(Arrays.toString(tickLocations.toArray())); assertThat(tickLocations.size(), equalTo(7)); - assertThat(tickLocations.get(0), equalTo(15)); + assertThat(tickLocations.get(0), equalTo(15.0)); } }