From d2973bc3d0921de8dc95fcea5f6b32d3007ca114 Mon Sep 17 00:00:00 2001 From: Tim Molter <tim@knowm.org> Date: Sun, 3 Jan 2016 14:13:48 +0100 Subject: [PATCH] Issue #26 - Pie Charts first cut --- .../org/knowm/xchart/demo/XChartDemo.java | 8 ++ .../xchart/demo/charts/pie/PieChart01.java | 56 ++++++++ .../src/main/java/org/knowm/xchart/Chart.java | 12 ++ .../main/java/org/knowm/xchart/Series.java | 2 +- .../java/org/knowm/xchart/StyleManager.java | 2 +- .../knowm/xchart/internal/chartpart/Axis.java | 31 ++++- .../xchart/internal/chartpart/AxisPair.java | 4 +- .../internal/chartpart/ChartInternal.java | 38 +++++- .../xchart/internal/chartpart/Legend.java | 25 ++-- .../knowm/xchart/internal/chartpart/Plot.java | 4 + .../PlotContentCategoricalChart_Bar.java | 5 +- ...entCategoricalChart_Line_Area_Scatter.java | 6 +- .../PlotContentCategoricalChart_Pie.java | 129 ++++++++++++++++++ .../chartpart/PlotContentNumericalChart.java | 3 +- .../internal/chartpart/PlotSurface.java | 3 + .../xchart/internal/style/XChartTheme.java | 3 +- 16 files changed, 300 insertions(+), 31 deletions(-) create mode 100644 xchart-demo/src/main/java/org/knowm/xchart/demo/charts/pie/PieChart01.java create mode 100644 xchart/src/main/java/org/knowm/xchart/internal/chartpart/PlotContentCategoricalChart_Pie.java diff --git a/xchart-demo/src/main/java/org/knowm/xchart/demo/XChartDemo.java b/xchart-demo/src/main/java/org/knowm/xchart/demo/XChartDemo.java index f2e23655..37ac297c 100644 --- a/xchart-demo/src/main/java/org/knowm/xchart/demo/XChartDemo.java +++ b/xchart-demo/src/main/java/org/knowm/xchart/demo/XChartDemo.java @@ -59,6 +59,7 @@ import org.knowm.xchart.demo.charts.line.LineChart04; import org.knowm.xchart.demo.charts.line.LineChart05; import org.knowm.xchart.demo.charts.line.LineChart06; import org.knowm.xchart.demo.charts.line.LineChart07; +import org.knowm.xchart.demo.charts.pie.PieChart01; import org.knowm.xchart.demo.charts.realtime.RealtimeChart01; import org.knowm.xchart.demo.charts.realtime.RealtimeChart02; import org.knowm.xchart.demo.charts.realtime.RealtimeChart03; @@ -219,6 +220,13 @@ public class XChartDemo extends JPanel implements TreeSelectionListener { defaultMutableTreeNode = new DefaultMutableTreeNode(new ChartInfo("AreaLineChart03 - Combination Area & Line Chart", new AreaLineChart03().getChart())); category.add(defaultMutableTreeNode); + // Pie category + category = new DefaultMutableTreeNode("Pie Charts"); + top.add(category); + + defaultMutableTreeNode = new DefaultMutableTreeNode(new ChartInfo("PieChart01 - Pie Chart with 4 Slices", new PieChart01().getChart())); + category.add(defaultMutableTreeNode); + // Line category category = new DefaultMutableTreeNode("Line Charts"); top.add(category); diff --git a/xchart-demo/src/main/java/org/knowm/xchart/demo/charts/pie/PieChart01.java b/xchart-demo/src/main/java/org/knowm/xchart/demo/charts/pie/PieChart01.java new file mode 100644 index 00000000..a30d580a --- /dev/null +++ b/xchart-demo/src/main/java/org/knowm/xchart/demo/charts/pie/PieChart01.java @@ -0,0 +1,56 @@ +/** + * Copyright 2015 Knowm Inc. (http://knowm.org) and contributors. + * Copyright 2011-2015 Xeiam LLC (http://xeiam.com) and contributors. + * + * 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 org.knowm.xchart.demo.charts.pie; + +import org.knowm.xchart.Chart; +import org.knowm.xchart.ChartBuilder; +import org.knowm.xchart.StyleManager.ChartType; +import org.knowm.xchart.SwingWrapper; +import org.knowm.xchart.demo.charts.ExampleChart; + +/** + * Pie Chart with 4 Slices + * <p> + * Demonstrates the following: + * <ul> + * <li>Pie Chart + * <li>ChartBuilder + */ +public class PieChart01 implements ExampleChart { + + public static void main(String[] args) { + + ExampleChart exampleChart = new PieChart01(); + Chart chart = exampleChart.getChart(); + new SwingWrapper(chart).displayChart(); + } + + @Override + public Chart getChart() { + + // Create Chart + // TODO remove chartType(ChartType.Pie) + Chart chart = new ChartBuilder().chartType(ChartType.Pie).width(800).height(600).title(getClass().getSimpleName()).xAxisTitle("X").yAxisTitle("Y").build(); + chart.addPieSeries("Pennies", 387); + chart.addPieSeries("Nickels", 234); + chart.addPieSeries("Dimes", 190); + chart.addPieSeries("Quarters", 270); + + return chart; + } + +} diff --git a/xchart/src/main/java/org/knowm/xchart/Chart.java b/xchart/src/main/java/org/knowm/xchart/Chart.java index fa8bfef7..d8714285 100644 --- a/xchart/src/main/java/org/knowm/xchart/Chart.java +++ b/xchart/src/main/java/org/knowm/xchart/Chart.java @@ -159,6 +159,18 @@ public class Chart { return addCategorySeries(seriesName, xData, yData, null); } + /** + * Add a series for a Pie type chart + * + * @param seriesName + * @param value + * @return + */ + public Series addPieSeries(String seriesName, Number value) { + + return chartInternal.addPieSeries(seriesName, value); + } + /** * Add a series for a X-Y type chart using using double arrays * diff --git a/xchart/src/main/java/org/knowm/xchart/Series.java b/xchart/src/main/java/org/knowm/xchart/Series.java index 63fa0799..574c71cb 100644 --- a/xchart/src/main/java/org/knowm/xchart/Series.java +++ b/xchart/src/main/java/org/knowm/xchart/Series.java @@ -35,7 +35,7 @@ import org.knowm.xchart.internal.style.SeriesColorMarkerLineStyle; public class Series { public enum SeriesType { - Line, Scatter, Area, Bar + Line, Scatter, Area, Bar, Pie } private SeriesType seriesType = null; diff --git a/xchart/src/main/java/org/knowm/xchart/StyleManager.java b/xchart/src/main/java/org/knowm/xchart/StyleManager.java index 8cb0d314..b7c0acfb 100644 --- a/xchart/src/main/java/org/knowm/xchart/StyleManager.java +++ b/xchart/src/main/java/org/knowm/xchart/StyleManager.java @@ -37,7 +37,7 @@ public class StyleManager { public enum ChartType { - Line, Scatter, Area, Bar + Line, Scatter, Area, Bar, Pie } public enum LegendPosition { diff --git a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/Axis.java b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/Axis.java index c16af11a..5eeb5075 100644 --- a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/Axis.java +++ b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/Axis.java @@ -144,6 +144,12 @@ public class Axis implements ChartPart { // determine Axis bounds if (direction == Direction.Y) { // Y-Axis - gets called first + if (getChartInternal().getChartInternalType() == ChartInternalType.Pie) { + bounds = new Rectangle2D.Double(getChartInternal().getStyleManager().getChartPadding(), getChartInternal().getChartTitle().getSizeHint(), 0, getChartInternal().getHeight() - getChartInternal() + .getChartTitle().getSizeHint() - getChartInternal().getStyleManager().getPlotPadding() - getChartInternal().getStyleManager().getChartPadding()); + return; + } + // first determine the height of // calculate paint zone @@ -213,6 +219,13 @@ public class Axis implements ChartPart { } else { // X-Axis + if (getChartInternal().getChartInternalType() == ChartInternalType.Pie) { + bounds = new Rectangle2D.Double(getChartInternal().getStyleManager().getChartPadding(), getChartInternal().getHeight() - getChartInternal().getStyleManager().getChartPadding(), + getChartInternal().getWidth() - getChartInternal().getChartTitle().getSizeHint() - getChartInternal().getStyleManager().getPlotPadding() - (getChartInternal().getStyleManager() + .getLegendPosition() == LegendPosition.OutsideE ? getChartInternal().getChartLegend().getLegendBoxWidth() : 0), 0); + return; + } + // calculate paint zone // |____________________| @@ -271,6 +284,10 @@ public class Axis implements ChartPart { */ private double getXAxisHeightHint(double workingSpace) { + if (getChartInternal().getChartInternalType() == ChartInternalType.Pie) { + return 0.0; + } + // Axis title double titleHeight = 0.0; if (axisTitle.getText() != null && !axisTitle.getText().trim().equalsIgnoreCase("") && getChartInternal().getStyleManager().isXAxisTitleVisible()) { @@ -287,6 +304,7 @@ public class Axis implements ChartPart { // System.out.println("XAxisHeightHint"); // System.out.println("workingSpace: " + workingSpace); this.axisTickCalculator = getAxisTickCalculator(workingSpace); + String sampleLabel = ""; // find the longest String in all the labels for (int i = 0; i < axisTickCalculator.getTickLabels().size(); i++) { @@ -311,6 +329,10 @@ public class Axis implements ChartPart { private double getYAxisWidthHint(double workingSpace) { + if (getChartInternal().getChartInternalType() == ChartInternalType.Pie) { + return 0.0; + } + // Axis title double titleHeight = 0.0; if (axisTitle.getText() != null && !axisTitle.getText().trim().equalsIgnoreCase("") && getChartInternal().getStyleManager().isYAxisTitleVisible()) { @@ -327,6 +349,7 @@ public class Axis implements ChartPart { // System.out.println("XAxisHeightHint"); // System.out.println("workingSpace: " + workingSpace); this.axisTickCalculator = getAxisTickCalculator(workingSpace); + String sampleLabel = ""; // find the longest String in all the labels for (int i = 0; i < axisTickCalculator.getTickLabels().size(); i++) { @@ -355,6 +378,9 @@ public class Axis implements ChartPart { AxisType axisType = getChartInternal().getAxisPair().getXAxis().getAxisType(); return new AxisTickCalculator_Category(getDirection(), workingSpace, categories, axisType, getChartInternal().getStyleManager()); } + else if (getChartInternal().getChartInternalType() == ChartInternalType.Pie) { + return null; + } else if (getChartInternal().getChartInternalType() == ChartInternalType.XY && getAxisType() == AxisType.Date) { return new AxisTickCalculator_Date(getDirection(), workingSpace, min, max, getChartInternal().getStyleManager()); @@ -372,7 +398,10 @@ public class Axis implements ChartPart { // Y-Axis else { - if (getChartInternal().getStyleManager().isYAxisLogarithmic() && getAxisType() != AxisType.Date) { + if (getChartInternal().getChartInternalType() == ChartInternalType.Pie) { + return null; + } + else if (getChartInternal().getStyleManager().isYAxisLogarithmic() && getAxisType() != AxisType.Date) { return new AxisTickCalculator_Logarithmic(getDirection(), workingSpace, min, max, getChartInternal().getStyleManager()); } diff --git a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/AxisPair.java b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/AxisPair.java index f20e7c1c..ca45d6ff 100644 --- a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/AxisPair.java +++ b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/AxisPair.java @@ -17,7 +17,7 @@ package org.knowm.xchart.internal.chartpart; import java.awt.Graphics2D; -import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; /** * @author timmolter @@ -52,7 +52,7 @@ public class AxisPair implements ChartPart { } @Override - public Rectangle getBounds() { + public Rectangle2D getBounds() { return null; // should never be called } diff --git a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/ChartInternal.java b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/ChartInternal.java index ca568917..c3780597 100644 --- a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/ChartInternal.java +++ b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/ChartInternal.java @@ -21,6 +21,7 @@ import java.awt.RenderingHints; import java.awt.Shape; import java.awt.geom.Rectangle2D; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.Iterator; import java.util.LinkedHashMap; @@ -41,7 +42,7 @@ public class ChartInternal { protected enum ChartInternalType { - XY, Category + XY, Category, Pie } private ChartInternalType chartInternalType = null; @@ -85,7 +86,7 @@ public class ChartInternal { public Series addSeries(String seriesName, List<?> xData, List<? extends Number> yData, List<? extends Number> errorBars) { if (chartInternalType != null && chartInternalType != ChartInternalType.XY) { - throw new IllegalArgumentException("Cannot mix x-y and category series types! Don't call addSeries() and addCategorySeries() for the same chart!"); + throw new IllegalArgumentException("Cannot mix x-y, category and/or pie series types! Don't call addSeries() and/or addCategorySeries() and/or addPieSeries() for the same chart!"); } chartInternalType = ChartInternalType.XY; @@ -143,7 +144,7 @@ public class ChartInternal { public Series addCategorySeries(String seriesName, List<?> xData, List<? extends Number> yData, List<? extends Number> errorBars) { if (chartInternalType != null && chartInternalType != ChartInternalType.Category) { - throw new IllegalArgumentException("Cannot mix x-y and category series types! Don't call addSeries() and addCategorySeries() for the same chart!"); + throw new IllegalArgumentException("Cannot mix x-y, category and/or pie series types! Don't call addSeries() and/or addCategorySeries() and/or addPieSeries() for the same chart!"); } chartInternalType = ChartInternalType.Category; @@ -161,7 +162,6 @@ public class ChartInternal { throw new IllegalArgumentException("X-Axis data must exactly match all other Series X-Axis data for Category Charts!!"); } } - // TODO make sure pie charts only have one series! // inspect the series to see what kind of data it contains (Number, Date, String) setXAxisType(xData); @@ -176,12 +176,35 @@ public class ChartInternal { if (seriesMap.keySet().contains(seriesName)) { throw new IllegalArgumentException("Series name >" + seriesName + "< has already been used. Use unique names for each series!!!"); } - seriesMap.put(seriesName, series); return series; } + public Series addPieSeries(String sliceName, Number value) { + + if (chartInternalType != null && chartInternalType != ChartInternalType.Pie) { + throw new IllegalArgumentException("Cannot mix x-y, category and/or pie series types! Don't call addSeries() and/or addCategorySeries() and/or addPieSeries() for the same chart!"); + } + chartInternalType = ChartInternalType.Pie; + + axisPair.getXAxis().setAxisType(AxisType.String); + + axisPair.getYAxis().setAxisType(AxisType.Number); + Series series = new Series(sliceName, Arrays.asList(new String[] { sliceName }), axisPair.getXAxis().getAxisType(), Arrays.asList(new Number[] { value }), axisPair.getYAxis().getAxisType(), null, + styleManager.getSeriesColorMarkerLineStyleCycler().getNextSeriesColorMarkerLineStyle()); + + // set series type + setSeriesType(series); + + if (seriesMap.keySet().contains(sliceName)) { + throw new IllegalArgumentException("Series name >" + sliceName + "< has already been used. Use unique names for each series!!!"); + } + seriesMap.put(sliceName, series); + + return series; + } + private void sanityCheck(String seriesName, List<?> xData, List<? extends Number> yData, List<? extends Number> errorBars) { if (seriesName == null) { @@ -260,6 +283,11 @@ public class ChartInternal { series.setSeriesType(Series.SeriesType.Bar); } break; + case Pie: + if (series.getSeriesType() == null) { + series.setSeriesType(Series.SeriesType.Pie); + } + break; default: if (series.getSeriesType() == null) { series.setSeriesType(Series.SeriesType.Line); diff --git a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/Legend.java b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/Legend.java index 05b236f1..80ef017a 100644 --- a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/Legend.java +++ b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/Legend.java @@ -70,7 +70,7 @@ public class Legend implements ChartPart { return; } - boolean containsBar = false; + boolean containsBarOrPie = false; // determine legend text content max width double legendTextContentMaxWidth = 0; @@ -89,18 +89,19 @@ public class Legend implements ChartPart { } blockHeight -= MULTI_LINE_SPACE; - blockHeight = Math.max(blockHeight, series.getSeriesType() == Series.SeriesType.Bar ? BOX_SIZE : getChartInternal().getStyleManager().getMarkerSize()); + blockHeight = Math.max(blockHeight, (series.getSeriesType() == Series.SeriesType.Bar || series.getSeriesType() == Series.SeriesType.Pie) ? BOX_SIZE : getChartInternal().getStyleManager() + .getMarkerSize()); legendContentHeight += blockHeight + getChartInternal().getStyleManager().getLegendPadding(); - if (series.getSeriesType() == Series.SeriesType.Bar) { - containsBar = true; + if (series.getSeriesType() == Series.SeriesType.Bar || series.getSeriesType() == Series.SeriesType.Pie) { + containsBarOrPie = true; } } // determine legend content width double legendContentWidth = 0; - if (!containsBar) { + if (!containsBarOrPie) { legendContentWidth = getChartInternal().getStyleManager().getLegendSeriesLineLength() + getChartInternal().getStyleManager().getLegendPadding() + legendTextContentMaxWidth; } else { @@ -184,9 +185,10 @@ public class Legend implements ChartPart { } blockHeight -= MULTI_LINE_SPACE; - blockHeight = Math.max(blockHeight, series.getSeriesType() == Series.SeriesType.Bar ? BOX_SIZE : getChartInternal().getStyleManager().getMarkerSize()); + blockHeight = Math.max(blockHeight, (series.getSeriesType() == Series.SeriesType.Bar || series.getSeriesType() == Series.SeriesType.Pie) ? BOX_SIZE : getChartInternal().getStyleManager() + .getMarkerSize()); - if (series.getSeriesType() != Series.SeriesType.Bar) { + if (series.getSeriesType() != Series.SeriesType.Bar && series.getSeriesType() != Series.SeriesType.Pie) { // paint line if (series.getSeriesType() != Series.SeriesType.Scatter && series.getStroke() != null) { @@ -205,11 +207,12 @@ public class Legend implements ChartPart { // paint marker if (series.getMarker() != null) { g.setColor(series.getMarkerColor()); - series.getMarker().paint(g, startx + getChartInternal().getStyleManager().getLegendSeriesLineLength() / 2.0, starty + blockHeight / 2.0, getChartInternal().getStyleManager().getMarkerSize()); + series.getMarker().paint(g, startx + getChartInternal().getStyleManager().getLegendSeriesLineLength() / 2.0, starty + blockHeight / 2.0, getChartInternal().getStyleManager() + .getMarkerSize()); } } - else { // bar type series + else { // bar/pie type series // paint little box if (series.getStroke() != null) { @@ -229,7 +232,7 @@ public class Legend implements ChartPart { double multiLineOffset = 0.0; - if (series.getSeriesType() != Series.SeriesType.Bar) { + if (series.getSeriesType() != Series.SeriesType.Bar && series.getSeriesType() != Series.SeriesType.Pie) { double x = startx + getChartInternal().getStyleManager().getLegendSeriesLineLength() + getChartInternal().getStyleManager().getLegendPadding(); for (Map.Entry<String, Rectangle2D> entry : seriesTextBounds.entrySet()) { @@ -257,7 +260,7 @@ public class Legend implements ChartPart { starty += blockHeight + getChartInternal().getStyleManager().getLegendPadding(); } - else { // bar type series + else { // bar/pie type series final double x = startx + BOX_SIZE + getChartInternal().getStyleManager().getLegendPadding(); for (Map.Entry<String, Rectangle2D> entry : seriesTextBounds.entrySet()) { diff --git a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/Plot.java b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/Plot.java index fd7abb3c..0dfb9a8a 100644 --- a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/Plot.java +++ b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/Plot.java @@ -81,10 +81,14 @@ public class Plot implements ChartPart { if (getChartInternal().getStyleManager().getChartType() == ChartType.Bar) { this.plotContent = new PlotContentCategoricalChart_Bar(this); } + else { this.plotContent = new PlotContentCategoricalChart_Line_Area_Scatter(this); } } + else if (getChartInternal().getChartInternalType() == ChartInternalType.Pie) { + this.plotContent = new PlotContentCategoricalChart_Pie(this); + } else { this.plotContent = new PlotContentNumericalChart(this); } diff --git a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/PlotContentCategoricalChart_Bar.java b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/PlotContentCategoricalChart_Bar.java index 059b399e..8a9470a6 100644 --- a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/PlotContentCategoricalChart_Bar.java +++ b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/PlotContentCategoricalChart_Bar.java @@ -17,7 +17,6 @@ package org.knowm.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; @@ -58,7 +57,7 @@ public class PlotContentCategoricalChart_Bar extends PlotContent { // g.draw(bounds); // this is for preventing the series to be drawn outside the plot area if min and max is overridden to fall inside the data range - Rectangle rectangle = new Rectangle(0, 0, getChartInternal().getWidth(), getChartInternal().getHeight()); + Rectangle2D rectangle = new Rectangle2D.Double(0, 0, getChartInternal().getWidth(), getChartInternal().getHeight()); // g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); // g.setColor(Color.green); // g.draw(rectangle); @@ -99,7 +98,7 @@ public class PlotContentCategoricalChart_Bar extends PlotContent { for (Series series : getChartInternal().getSeriesMap().values()) { // sanity check - if (Series.SeriesType.Area.equals(series.getSeriesType())) { + if (Series.SeriesType.Area.equals(series.getSeriesType()) || Series.SeriesType.Pie.equals(series.getSeriesType())) { throw new RuntimeException("Category-Bar charts only accept Bar, Line and Scatter series types!!!"); } diff --git a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/PlotContentCategoricalChart_Line_Area_Scatter.java b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/PlotContentCategoricalChart_Line_Area_Scatter.java index 6baa1f65..e8be8fe0 100644 --- a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/PlotContentCategoricalChart_Line_Area_Scatter.java +++ b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/PlotContentCategoricalChart_Line_Area_Scatter.java @@ -17,7 +17,6 @@ package org.knowm.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; @@ -68,7 +67,7 @@ public class PlotContentCategoricalChart_Line_Area_Scatter extends PlotContent { // g.setColor(Color.green); // g.draw(rectangle); - Rectangle rectangle = new Rectangle(0, 0, getChartInternal().getWidth(), getChartInternal().getHeight()); + Rectangle2D rectangle = new Rectangle2D.Double(0, 0, getChartInternal().getWidth(), getChartInternal().getHeight()); // g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); // g.setColor(Color.green); // g.draw(rectangle); @@ -105,7 +104,8 @@ public class PlotContentCategoricalChart_Line_Area_Scatter extends PlotContent { for (Series series : getChartInternal().getSeriesMap().values()) { // sanity check - if (Series.SeriesType.Bar.equals(series.getSeriesType())) { + + if (Series.SeriesType.Bar.equals(series.getSeriesType()) || Series.SeriesType.Pie.equals(series.getSeriesType())) { throw new RuntimeException("Category-Line,Scatter,Area charts only accept Line, Scatter, and Area series types!!!"); } diff --git a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/PlotContentCategoricalChart_Pie.java b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/PlotContentCategoricalChart_Pie.java new file mode 100644 index 00000000..5d694dc2 --- /dev/null +++ b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/PlotContentCategoricalChart_Pie.java @@ -0,0 +1,129 @@ +/** + * Copyright 2015 Knowm Inc. (http://knowm.org) and contributors. + * Copyright 2011-2015 Xeiam LLC (http://xeiam.com) and contributors. + * + * 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 org.knowm.xchart.internal.chartpart; + +import java.awt.Graphics2D; +import java.awt.geom.Arc2D; +import java.awt.geom.Rectangle2D; + +import org.knowm.xchart.Series; + +/** + * @author timmolter + */ +public class PlotContentCategoricalChart_Pie extends PlotContent { + + /** + * Constructor + * + * @param plot + */ + protected PlotContentCategoricalChart_Pie(Plot plot) { + + super(plot); + } + + @Override + public void paint(Graphics2D g) { + + // plot area bounds + Rectangle2D bounds = plot.getBounds(); + // g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); + // g.setColor(Color.red); + // g.draw(bounds); + + // if the area to draw a chart on is so small, don't even bother + if (bounds.getWidth() < 30) { + return; + } + + // clip bounds TODO Do we need this? + Rectangle2D rectangle = new Rectangle2D.Double(0, 0, getChartInternal().getWidth(), getChartInternal().getHeight()); + // g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); + // g.setColor(Color.green); + // g.draw(rectangle); + g.setClip(bounds.createIntersection(rectangle)); + + // pie bounds + double percentage = .70; + double halfBorderPercentage = (1 - percentage) / 2.0; + Rectangle2D pieBounds = new Rectangle2D.Double(bounds.getX() + bounds.getWidth() * halfBorderPercentage, bounds.getY() + bounds.getHeight() * halfBorderPercentage, bounds.getWidth() * percentage, + bounds.getHeight() * percentage); + // g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); + // g.setColor(Color.black); + // g.draw(pieBounds); + + // get total + double total = 0.0; + for (Series series : getChartInternal().getSeriesMap().values()) { + + String x = (String) series.getXData().iterator().next(); + Number y = series.getYData().iterator().next(); + + total += y.doubleValue(); + } + + // draw pie slices + double curValue = 0.0; + double startAngle = 0; + for (Series series : getChartInternal().getSeriesMap().values()) { + + // String x = (String) series.getXData().iterator().next(); + Number y = series.getYData().iterator().next(); + + startAngle = (curValue * 360 / total); + double arcAngle = (y.doubleValue() * 360 / total); + g.setColor(series.getFillColor()); + g.fill(new Arc2D.Double(pieBounds.getX(), pieBounds.getY(), pieBounds.getWidth(), pieBounds.getHeight(), startAngle, arcAngle, Arc2D.PIE)); + g.setColor(getChartInternal().getStyleManager().getPlotBackgroundColor()); + g.draw(new Arc2D.Double(pieBounds.getX(), pieBounds.getY(), pieBounds.getWidth(), pieBounds.getHeight(), startAngle, arcAngle, Arc2D.PIE)); + curValue += y.doubleValue(); + } + + g.setClip(null); + + } + + // private double[] getPercentageVector(Collection<? extends Number> collection) { + // + // float total = 0.0f; + // + // double[] vectorCenters = new double[collection.size()]; + // Iterator<? extends Number> yItr = collection.iterator(); + // + // int counter = 0; + // while (yItr.hasNext()) { + // + // Number next = yItr.next(); + // + // double y = next.doubleValue(); + // System.out.println(y); + // vectorCenters[counter] = vectorCenters[counter] + y; + // + // total += vectorCenters[counter++]; + // } + // + // double[] vectorPercentages = new double[vectorCenters.length]; + // + // for (int i = 0; i < vectorPercentages.length; i++) { + // vectorPercentages[i] = vectorCenters[i] / total; + // } + // + // return vectorPercentages; + // } + +} diff --git a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/PlotContentNumericalChart.java b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/PlotContentNumericalChart.java index 4c092520..ac9a5c85 100644 --- a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/PlotContentNumericalChart.java +++ b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/PlotContentNumericalChart.java @@ -17,7 +17,6 @@ package org.knowm.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; @@ -65,7 +64,7 @@ public class PlotContentNumericalChart extends PlotContent { // g.setColor(Color.green); // g.draw(rectangle); - Rectangle rectangle = new Rectangle(0, 0, getChartInternal().getWidth(), getChartInternal().getHeight()); + Rectangle2D rectangle = new Rectangle2D.Double(0, 0, getChartInternal().getWidth(), getChartInternal().getHeight()); // g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); // g.setColor(Color.green); // g.draw(rectangle); diff --git a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/PlotSurface.java b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/PlotSurface.java index f969f59f..ad6f11f5 100644 --- a/xchart/src/main/java/org/knowm/xchart/internal/chartpart/PlotSurface.java +++ b/xchart/src/main/java/org/knowm/xchart/internal/chartpart/PlotSurface.java @@ -69,6 +69,9 @@ public class PlotSurface implements ChartPart { } // paint grid lines and/or inner plot ticks + if (getChartInternal().getAxisPair().getYAxis().getAxisTickCalculator() == null) {// like for Pie Charts + return; + } // horizontal if (getChartInternal().getStyleManager().isPlotGridHorizontalLinesVisible() || getChartInternal().getStyleManager().isPlotTicksMarksVisible()) { diff --git a/xchart/src/main/java/org/knowm/xchart/internal/style/XChartTheme.java b/xchart/src/main/java/org/knowm/xchart/internal/style/XChartTheme.java index 4e1a04eb..ff561f75 100644 --- a/xchart/src/main/java/org/knowm/xchart/internal/style/XChartTheme.java +++ b/xchart/src/main/java/org/knowm/xchart/internal/style/XChartTheme.java @@ -35,6 +35,7 @@ import org.knowm.xchart.StyleManager.LegendPosition; */ public class XChartTheme implements Theme { + // original XChart colors // public static SeriesColor BLUE = new SeriesColor(0, 55, 255, 180); // public static SeriesColor ORANGE = new SeriesColor(255, 172, 0, 180); // public static SeriesColor PURPLE = new SeriesColor(128, 0, 255, 180); @@ -58,8 +59,6 @@ public class XChartTheme implements Theme { // public static SeriesColor BROWN = new SeriesColor(166, 86, 40, 180); // public static SeriesColor PINK = new SeriesColor(247, 129, 191, 180); - // ['rgb(228,26,28)','rgb(55,126,184)','rgb(77,175,74)','rgb(152,78,163)','rgb(255,127,0)','rgb(255,255,51)','rgb(166,86,40)','rgb(247,129,191)'] - // Chart Style /////////////////////////////// @Override -- GitLab