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