Skip to content
Snippets Groups Projects
Commit 95f4970a authored by Tim Molter's avatar Tim Molter
Browse files

Merge branch 'develop'

parents 6aff356b 1d9850e7
No related branches found
No related tags found
No related merge requests found
Showing
with 593 additions and 56 deletions
......@@ -102,3 +102,4 @@ Please report any bugs or submit feature requests to [XChart's Github issue trac
## Donations
1PrZHiJorAw7RQrjP9CJgtPuqr6fU65PKt
......@@ -4,7 +4,7 @@
<groupId>com.xeiam.xchart</groupId>
<artifactId>xchart-parent</artifactId>
<version>2.3.2-SNAPSHOT</version>
<version>2.3.3-SNAPSHOT</version>
<packaging>pom</packaging>
<name>XChart Parent</name>
<description>Basic Charts for Java Applications</description>
......
......@@ -5,7 +5,7 @@
<parent>
<groupId>com.xeiam.xchart</groupId>
<artifactId>xchart-parent</artifactId>
<version>2.3.2-SNAPSHOT</version>
<version>2.3.3-SNAPSHOT</version>
</parent>
<artifactId>xchart-demo</artifactId>
......@@ -17,7 +17,7 @@
<dependency>
<groupId>com.xeiam.xchart</groupId>
<artifactId>xchart</artifactId>
<version>2.3.2-SNAPSHOT</version>
<version>2.3.3-SNAPSHOT</version>
</dependency>
</dependencies>
......
......@@ -38,6 +38,8 @@ import com.xeiam.xchart.demo.charts.bar.BarChart02;
import com.xeiam.xchart.demo.charts.bar.BarChart03;
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.date.DateChart01;
import com.xeiam.xchart.demo.charts.date.DateChart02;
import com.xeiam.xchart.demo.charts.date.DateChart03;
......@@ -78,8 +80,8 @@ public class XChartDemo extends JPanel implements TreeSelectionListener {
private XChartPanel chartPanel;
/** real-time chart example */
final RealtimeChart01 realtimeChart01 = new RealtimeChart01();;
final RealtimeChart02 realtimeChart02 = new RealtimeChart02();;
final RealtimeChart01 realtimeChart01 = new RealtimeChart01();
final RealtimeChart02 realtimeChart02 = new RealtimeChart02();
Timer timer = new Timer();
/**
......@@ -192,7 +194,7 @@ public class XChartDemo extends JPanel implements TreeSelectionListener {
defaultMutableTreeNode = new DefaultMutableTreeNode(new ChartInfo("AreaChart02 - Null Y-Axis Data Points", new AreaChart02().getChart()));
category.add(defaultMutableTreeNode);
// First category
// Line category
category = new DefaultMutableTreeNode("Line Charts");
top.add(category);
......@@ -249,6 +251,12 @@ public class XChartDemo extends JPanel implements TreeSelectionListener {
defaultMutableTreeNode = new DefaultMutableTreeNode(new ChartInfo("BarChart05 - GGPlot2 Theme", new BarChart05().getChart()));
category.add(defaultMutableTreeNode);
defaultMutableTreeNode = new DefaultMutableTreeNode(new ChartInfo("BarChart06 - Histogram Overlapped", new BarChart06().getChart()));
category.add(defaultMutableTreeNode);
defaultMutableTreeNode = new DefaultMutableTreeNode(new ChartInfo("BarChart07 - Histogram Not Overlapped", new BarChart07().getChart()));
category.add(defaultMutableTreeNode);
// Theme category
category = new DefaultMutableTreeNode("Chart Themes");
top.add(category);
......
......@@ -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);
......
/**
* 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 Overlapped
* <p>
* Demonstrates the following:
* <ul>
* <li>Histogram
* <li>Bar Chart styles - overlapped, bar width
*/
public class BarChart06 implements ExampleChart {
public static void main(String[] args) {
ExampleChart exampleChart = new BarChart06();
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("Score Histogram").xAxisTitle("Mean").yAxisTitle("Count").build();
Histogram histogram1 = new Histogram(getGaussianData(10000), 30, -30, 30);
Histogram histogram2 = new Histogram(getGaussianData(5000), 30, -30, 30);
chart.addSeries("histogram 1", histogram1.getxAxisData(), histogram1.getyAxisData());
chart.addSeries("histogram 2", histogram2.getxAxisData(), histogram2.getyAxisData());
// Customize Chart
chart.getStyleManager().setLegendPosition(LegendPosition.InsideNW);
chart.getStyleManager().setBarWidthPercentage(.96);
chart.getStyleManager().setBarsOverlapped(true);
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() * 10);
// data.add(r.nextDouble() * 60 - 30);
}
return data;
}
}
/**
* 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 Not Overlapped
* <p>
* Demonstrates the following:
* <ul>
* <li>Histogram
* <li>Bar Chart styles - not overlapped, bar width
* <li>Integer data values
*/
public class BarChart07 implements ExampleChart {
public static void main(String[] args) {
ExampleChart exampleChart = new BarChart07();
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("Score Histogram").xAxisTitle("Mean").yAxisTitle("Count").build();
Histogram histogram1 = new Histogram(getGaussianData(1000), 10, -30, 30);
chart.addSeries("histogram 1", histogram1.getxAxisData(), histogram1.getyAxisData());
Histogram histogram2 = new Histogram(getGaussianData(1000), 10, -30, 30);
chart.addSeries("histogram 2", histogram2.getxAxisData(), histogram2.getyAxisData());
// Customize Chart
chart.getStyleManager().setLegendPosition(LegendPosition.InsideNW);
chart.getStyleManager().setBarWidthPercentage(.96);
return chart;
}
private List<Integer> getGaussianData(int count) {
List<Integer> data = new ArrayList<Integer>(count);
Random r = new Random();
for (int i = 0; i < count; i++) {
data.add((int) (r.nextGaussian() * 10));
// data.add(r.nextDouble() * 60 - 30);
}
return data;
}
}
......@@ -46,11 +46,11 @@ public class LineChart06 implements ExampleChart {
@Override
public Chart getChart() {
double[] xData = new double[] { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 };
int[] xData = new int[] { 0, 1, 2, 3, 4, 5, 6 };
double[] yData1 = new double[] { 100, 100, 100, 60, 10, 10, 10 };
int[] yData1 = new int[] { 100, 100, 100, 60, 10, 10, 10 };
double[] errdata = new double[] { 50, 20, 10, 52, 9, 2, 1 };
int[] errdata = new int[] { 50, 20, 10, 52, 9, 2, 1 };
Chart chart = new Chart(800, 600);
......
......@@ -5,7 +5,7 @@
<parent>
<groupId>com.xeiam.xchart</groupId>
<artifactId>xchart-parent</artifactId>
<version>2.3.2-SNAPSHOT</version>
<version>2.3.3-SNAPSHOT</version>
</parent>
<artifactId>xchart</artifactId>
......
......@@ -43,7 +43,6 @@ public class Chart {
public Chart(int width, int height) {
chartPainter = new ChartPainter(width, height);
}
/**
......@@ -176,6 +175,52 @@ public class Chart {
return chartPainter.getAxisPair().addSeries(seriesName, xDataNumber, yDataNumber, errorBarDataNumber);
}
/**
* Add a series to the chart using int arrays
*
* @param seriesName
* @param xData the X-Axis data
* @param xData the Y-Axis data
* @return A Series object that you can set properties on
*/
public Series addSeries(String seriesName, int[] xData, int[] yData) {
return addSeries(seriesName, xData, yData, null);
}
/**
* Add a series to the chart using int arrays with error bars
*
* @param seriesName
* @param xData the X-Axis data
* @param xData the Y-Axis data
* @param errorBars the error bar data
* @return A Series object that you can set properties on
*/
public Series addSeries(String seriesName, int[] xData, int[] yData, int[] errorBars) {
List<Double> xDataNumber = null;
if (xData != null) {
xDataNumber = new ArrayList<Double>();
for (int d : xData) {
xDataNumber.add(new Double(d));
}
}
List<Double> yDataNumber = new ArrayList<Double>();
for (int d : yData) {
yDataNumber.add(new Double(d));
}
List<Double> errorBarDataNumber = null;
if (errorBars != null) {
errorBarDataNumber = new ArrayList<Double>();
for (int d : errorBars) {
errorBarDataNumber.add(new Double(d));
}
}
return chartPainter.getAxisPair().addSeries(seriesName, xDataNumber, yDataNumber, errorBarDataNumber);
}
/**
* Set the chart title
*
......
/**
* Copyright 2013 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;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* This class can be used to create histogram data for histogram bar charts
*
* @author timmolter
*/
public class Histogram {
private List<Double> xAxisData; // bin centers
private List<Double> yAxisData; // frequency counts
private final Collection<? extends Number> originalData;
private final int numBins;
private final double min;
private final double max;
/**
* Constructor
*
* @param data
* @param numBins
*/
public Histogram(Collection<? extends Number> data, int numBins) {
this.numBins = numBins;
this.originalData = data;
List<Double> dataAsList = new ArrayList<Double>();
Iterator<? extends Number> itr = data.iterator();
while (itr.hasNext()) {
dataAsList.add(((Number) itr.next()).doubleValue());
}
Collections.sort(dataAsList);
this.min = dataAsList.get(0);
this.max = dataAsList.get(dataAsList.size() - 1);
init();
}
/**
* Constructor
*
* @param data
* @param numBins
* @param min
* @param max
*/
public Histogram(Collection<? extends Number> data, int numBins, double min, double max) {
this.numBins = numBins;
this.originalData = data;
// Arrays.sort(data);
this.min = min;
this.max = max;
// this.min = data[0];
// this.max = data[data.length - 1];
init();
}
private void init() {
double[] tempYAxisData = new double[numBins];
final double binSize = (max - min) / numBins;
// y axis data
Iterator<? extends Number> itr = originalData.iterator();
while (itr.hasNext()) {
int bin = (int) ((((Number) itr.next()).doubleValue() - min) / binSize); // changed this from numBins
if (bin < 0) { /* this data is smaller than min */
}
else if (bin >= numBins) { /* this data point is bigger than max */
}
else {
tempYAxisData[bin] += 1;
}
}
yAxisData = new ArrayList<Double>(numBins);
for (double d : tempYAxisData) {
yAxisData.add(new Double(d));
}
// x axis data
xAxisData = new ArrayList<Double>(numBins);
for (int i = 0; i < numBins; i++) {
xAxisData.add(((i * (max - min)) / numBins + min) + binSize / 2);
}
}
public List<Double> getxAxisData() {
return xAxisData;
}
public List<Double> getyAxisData() {
return yAxisData;
}
public Collection<? extends Number> getOriginalData() {
return originalData;
}
public int getNumBins() {
return numBins;
}
public double getMin() {
return min;
}
public double getMax() {
return max;
}
}
......@@ -127,6 +127,10 @@ public class StyleManager {
private Color plotGridLinesColor;
private Stroke plotGridLinesStroke;
// Bar Charts ///////////////////////////////
private double barWidthPercentage;
private boolean barsOverlapped;
// Error Bars ///////////////////////////////
private Color errorBarsColor;
......@@ -205,6 +209,10 @@ public class StyleManager {
plotGridLinesColor = theme.getPlotGridLinesColor();
plotGridLinesStroke = theme.getPlotGridLinesStroke();
// Bar Charts ///////////////////////////////
barWidthPercentage = theme.getBarWidthPercentage();
barsOverlapped = theme.barsOverlapped();
// Error Bars ///////////////////////////////
errorBarsColor = theme.getErrorBarsColor();
......@@ -850,10 +858,12 @@ public class StyleManager {
}
public void setAxisTickSpaceRatio(double axisTickSpaceRatio) {
this.axisTickSpaceRatio = axisTickSpaceRatio;
}
public double getAxisTickSpaceRatio() {
return axisTickSpaceRatio;
}
......@@ -964,6 +974,38 @@ public class StyleManager {
return plotGridLinesStroke;
}
// Bar Charts ///////////////////////////////
/**
* set the width of a single bar in a bar chart. full width is 100%, i.e. 1.0
*
* @param barWidthPercentage
*/
public void setBarWidthPercentage(double barWidthPercentage) {
this.barWidthPercentage = barWidthPercentage;
}
public double getBarWidthPercentage() {
return barWidthPercentage;
}
/**
* set whether or no bars are overlapped. Otherwise they are places side-by-side
*
* @param barsOverlapped
*/
public void setBarsOverlapped(boolean barsOverlapped) {
this.barsOverlapped = barsOverlapped;
}
public boolean barsOverlapped() {
return barsOverlapped;
}
// Error Bars ///////////////////////////////
/**
......
......@@ -29,6 +29,8 @@ import javax.swing.JPanel;
*/
public class SwingWrapper {
private String windowTitle = "XChart";
private List<Chart> charts = new ArrayList<Chart>();
private int numRows;
private int numColumns;
......@@ -70,13 +72,25 @@ public class SwingWrapper {
this.numColumns = numColumns;
}
/**
* Display the chart in a Swing JFrame
*
* @param windowTitle the title of the window
*/
public JFrame displayChart(String windowTitle) {
this.windowTitle = windowTitle;
return displayChart();
}
/**
* Display the chart in a Swing JFrame
*/
public JFrame displayChart() {
// Create and set up the window.
final JFrame frame = new JFrame("XChart");
final JFrame frame = new JFrame(windowTitle);
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
......@@ -98,13 +112,26 @@ public class SwingWrapper {
return frame;
}
/**
* Display the charts in a Swing JFrame
*
* @param windowTitle the title of the window
* @return the JFrame
*/
public JFrame displayChartMatrix(String windowTitle) {
this.windowTitle = windowTitle;
return displayChartMatrix();
}
/**
* Display the chart in a Swing JFrame
*/
public JFrame displayChartMatrix() {
// Create and set up the window.
final JFrame frame = new JFrame("XChart");
final JFrame frame = new JFrame(windowTitle);
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
......
......@@ -245,7 +245,7 @@ public class XChartPanel extends JPanel {
}
/**
* update a series by only updating the Y-Axis data. The X-Axis data will is automatically generated as a list of increasing Integers starting from 1 and ending at the size of the new Y-Axis data
* update a series by only updating the Y-Axis data. The X-Axis data will be automatically generated as a list of increasing Integers starting from 1 and ending at the size of the new Y-Axis data
* list.
*
* @param seriesName
......@@ -275,7 +275,7 @@ public class XChartPanel extends JPanel {
}
/**
* update a series by only updating both the X-Axis and Y-Axis data
* update a series by updating both the X-Axis and Y-Axis data
*
* @param seriesName
* @param newYData
......
......@@ -15,7 +15,6 @@
*/
package com.xeiam.xchart.internal;
/**
* @author timmolter
*/
......@@ -35,10 +34,10 @@ public class Utils {
* @param tickSpace
* @return
*/
public static int getTickStartOffset(int workingSpace, int tickSpace) {
public static double getTickStartOffset(double workingSpace, double tickSpace) {
int marginSpace = workingSpace - tickSpace;
return (int) (marginSpace / 2.0);
double marginSpace = workingSpace - tickSpace;
return marginSpace / 2.0;
}
public static double pow(double base, int exponent) {
......
......@@ -102,9 +102,9 @@ public class AxisPair implements ChartPart {
series = new Series(seriesName, xData, xAxis.getAxisType(), yData, yAxis.getAxisType(), errorBars, seriesColorMarkerLineStyleCycler.getNextSeriesColorMarkerLineStyle());
}
else { // generate xData
List<Number> generatedXData = new ArrayList<Number>();
List<Double> generatedXData = new ArrayList<Double>();
for (int i = 1; i < yData.size() + 1; i++) {
generatedXData.add(i);
generatedXData.add((double) i);
}
xAxis.setAxisType(AxisType.Number);
yAxis.setAxisType(AxisType.Number);
......
......@@ -152,7 +152,7 @@ public class AxisTick implements ChartPart {
return axisTickLabels;
}
public List<Integer> getTickLocations() {
public List<Double> getTickLocations() {
return gridStep.getTickLocations();
}
......
......@@ -53,23 +53,34 @@ public class AxisTickBarChartCalculator extends AxisTickCalculator {
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 margin = Utils.getTickStartOffset(workingSpace, tickSpace); // in plot space double gridStep = getGridStepForDecimal(tickSpace);
// 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);
......@@ -77,10 +88,21 @@ public class AxisTickBarChartCalculator extends AxisTickCalculator {
}
}
int numCategories = categories.size();
if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.String) {
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. give each category a tick label
int gridStep = (int) (tickSpace / (double) numCategories);
int firstPosition = (int) (gridStep / 2.0);
double gridStep = (tickSpace / (double) categories.size());
double firstPosition = gridStep / 2.0;
// generate all tickLabels and tickLocations from the first to last position
NumberFormatter numberFormatter = null;
......@@ -93,6 +115,7 @@ public class AxisTickBarChartCalculator extends AxisTickCalculator {
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));
......@@ -103,11 +126,41 @@ public class AxisTickBarChartCalculator extends AxisTickCalculator {
long timeUnit = dateFormatter.getTimeUnit(gridStepHint);
tickLabels.add(dateFormatter.formatDate((Double) category, timeUnit));
}
else if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.String) {
tickLabels.add(category.toString());
double tickLabelPosition = (int) (margin + firstPosition + gridStep * counter++);
tickLocations.add(tickLabelPosition);
}
int tickLabelPosition = margin + firstPosition + gridStep * counter++;
}
else { // Number or Date and more than 12 categories. divide up the axis tick space according to normal number axis layout
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) {
numberFormatter = new NumberFormatter(styleManager);
}
else if (chartPainter.getAxisPair().getXAxis().getAxisType() == AxisType.Date) {
dateFormatter = new DateFormatter(chartPainter.getStyleManager());
}
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));
}
double tickLabelPosition = margin + ((tickPosition - minValue) / (maxValue - minValue) * tickSpace);
tickLocations.add(tickLabelPosition);
}
}
}
}
......@@ -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(double 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;
}
}
......@@ -50,7 +50,7 @@ public class AxisTickDateCalculator extends AxisTickCalculator {
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 margin = Utils.getTickStartOffset(workingSpace, tickSpace); // in plot space double gridStep = getGridStepForDecimal(tickSpace);
// the span of the data
long span = (long) Math.abs(maxValue - minValue); // in data space
......@@ -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);
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment