## Introduction

The purpose of this article is to build a couple of simple pie chart controls. I am not trying to create anything fancy; just something which is simple to use and easy to learn.

Here is how the sample application, showing the use of the provided Pie Controls, looks like:

## Part-1: Using the Controls

Using the controls is straightforward. Two controls have been provided: `PieControl`

, which shows only the pie, and `PieChart`

, which contains both the pie and, additionally, the legend.

Creating the `PieControl`

(i.e., pie without the legend) and `PieChart`

is almost identical. You can create either of these by performing the following steps:

xmlns:pie="clr-namespace:PieControls;assembly=PieControls"

<StackPanel>
<pie:PieControl x:Name="pie1" Width="120" Height="120"/>
<pie:PiChart x:Name="chart1" Width="260" Height="140" PieWidth="120" PieHeight="120"/>
</StackPanel>

Be careful to use the same `Width`

and `Hight`

values for the `PieControl`

. For the `PieChart`

, `PieWidth`

and `PieHeight`

should be the same.

using PieControls;

ObservableCollection<PieSegment> pieCollection = new ObservableCollection<PieSegment>();
pieCollection.Add(new PieSegment { Color = Colors.Green, Value = 5, Name = "Dogs" });
pieCollection.Add(new PieSegment { Color = Colors.Yellow, Value = 12, Name = "Cats" });
pieCollection.Add(new PieSegment { Color = Colors.Red, Value = 20, Name = "Mice" });
pieCollection.Add(new PieSegment { Color = Colors.DarkCyan, Value = 22, Name = "Lizards" });
pie1.Data = pieCollection;
chart1.Data = pieCollection;

- Add references to the
**PieControls **and **Microsoft.Expression.Drawing** assemblies provided in the download. - Include the
`PieControls`

namespace in your XAML file. - Add the
`PieControl`

and/or the `PieChart`

to your Window/Control using something like this: - Include the 'using' statement in your code behind file
- 5. Populate the data for the pie chart in your code behind file and assign it to the pie controls like this:
- Make any changes you like to the
`pieCollection`

or any of its items anytime. They will be automatically reflected in the resulting Pie!

### 1.1. Customization Options

You can use the following to customize the controls:

- Properties of the class
`PieSegment`

. They are all designed to immediately change the pie view. `Width`

and `Height`

Properties of `PieControl`

and `PieChart`

. `PieWidth`

and `PieHeight`

Properties of `PieChart`

(these represent the width/height of the `PieControl`

contained within the `PieChart`

). `PopupBrush`

Property of `PieControl`

and `PieChart`

classes. This Property is used to paint the background of the popup that shows when you move your mouse cursor over the pie. - I have only used integral values in the sample just to keep it simple. The controls, however, internally use double precision floating point values; so your option is not limited to integers only.

## Part-2: Understanding the Source Code and the Math Behind

The file *PieControl.cs* in the attached source code contains the definition of our Pie Control. The other classes of interest are `PieChart`

and `PieSegment`

. `PieChart`

makes use of `PieControl`

and provides additional facility of a legend. The class `PieSegment`

is the data carrier used to communicate pie values to `PieChart`

and `PieControl`

.

A basic Pie is just a circle divided into smaller sectors according to the percentage of each data category. Each category having more than 0% share gets exactly one circle sector. 0 gets nothing, although we will keep the category there for possible future share it gets.

Imaging what we would do if we needed to create Pie charts for showing the share of our household expenses divided into 4 categories: (1) Food, (2) Clothing (3) Rent and (4) Entertainment. Here's is what we do:

- Calculate the sum of all the categories.
- Calculate the share (i.e., angle) of each category by dividing the share by the total and multiplying the result with 360 (a circle's full inner angle is 360 degrees).
- Determine the coordinates and draw each sector.

The first two steps are straightforward. The last step depends on how we will use the WPF primitives to create the Pie. Details will be shortly in place. First let's put theory into practice and do an example to see how the above steps are actually performed.

### Example

Suppose I spent the following amount of money on the given four categories in July, 2012.

- Food: $200
- Clothing: $160
- Rent: $280
- Entertainment $80

Here's how we will perform the earlier given three steps:

**1. Sum of all the categories:** 200 + 160 + 280 + 80 = **$720. **

**2. Share (angle) of each category:**

- **Food**: (200/720)*360=100 degrees

- **Clothing**:(160/720)*360=80 degrees

- **Rent**: (280/720)*360=140 degrees

- **Entertainment**: (80/720)*360=40 degrees

(100+80+140+40=360 degrees, the internal angle of the whole cirle/pie)

**3. Draw the sectors**:

This part is a bit involved. If you are not familiar with WPF drawing primitives, please first have a look at MSDN documentation for `Geometry`

and `Path `

classes; otherwise the following details will hardly make sense to you (I had a trouble understanding them while I was creating these controls. Only MSDN helped me out!). Follow this link for a good start. You may also need to have a look at the `ArcSegment`

class before proceeding (click here).

We will create a `Path`

object to represent each pie segment. The `Path`

object will draw the circle sector representing the pie segment as well as do hit testing (and track Mouse events) for us. If a single category gets all the share, the `Path`

will contain a single `EllipseGeometry`

. But in most cases there will be more than one category with more than 0% share. In such cases, the `Path`

will contain a `PathGeometry`

, which in turn will contain a `PathFigure`

and that `PathFigure`

will contain 2 `LineSegment`

s and 1 `ArcSegment`

as given below (these are all WPF classes):

LineSegment firstLineSegment = new LineSegment(startingPointOfArc, true);
ArcSegment arcSegment = new ArcSegment(endPointOfArc, pieSize, angleShare, angleShare > 180, SweepDirection.Clockwise, false);
LineSegment secondLineSegment = new LineSegment(centerPoint, true);
PathFigure pathFigure = new PathFigure(centerPoint, new PathSegment[] { firstLineSegment, arcSegment, secondLineSegment }, false);
PathGeometry pathGeometry = new PathGeometry();
pathGeometry.Figures.Add(pathFigure);
Path path = new Path();
path.Data = geometry;
myPanel.Children.Add(path);

Now we will try to understand what the code is doing. Remember that in the Constructors for `LineSegement`

and `ArcSegment`

the specified `Point`

objects represent the **End Point**. The **Start Point** is always implicit and is determined by where the previous segment ended. The first `LineSegment`

will get its Start Point from the containing `PathFigure`

. To draw each Pie segment, we will always start the `PathFigure`

at the center of the `PieControl`

. For convenience we make sure that our entire `PieControl`

is the size of the Pie. Also the Control must have the same `Width`

and `Height`

(our implementation does not support elliptical pie's). So the radius of the Pie will be Width/2 and the start point of pathFigure will be (radius, radius).

Now let's talk about calculating the coordinates of the line and arc segments. We need services of the `Math`

class to do the calculations. The `Math`

class uses **Radian **measure of angle while the WPF `Geometry`

classes use **Degrees**. So we will need to convert between the two measures. Two simple methods are provided in the source code for this conversion (in `PieControl`

class). Another twist is that, mathematically speaking, the angle starts at X-Axis; while we need to start the pie at 12'0 Clock (i.e. Right angle). We are drawing our figure clockwise, so we will adjust the coordinates by subtracting 90 degress while sweeping around the circumference.

Let's calculate the first sector representing **Food **(measuring 100 degrees). We will be ignoring round off errors to keep things simple. All the `Point`

objects given below represent `X`

and `Y`

coordinates in screen pixels relative to the containing Control.

(Remember the math starts at X-Axis, but we want to start our Pie at Right angle i.e. 90 degrees less, thinking clockwise)

`centerpoint`

= (100, 100) - this is the center of the Control/Pie, presuming our Pie is 200 pixels wide. - Start angle = -90 degrees = -PI/2 Radians = -1.57 Radians
`startingPointOfArc.X` = Math.Cos(-1.57) * 100 + 100 = 100 `startingPointOfArc.Y` = Math.Sin(-1.57) * 100 + 100 = 0 **Food **angle = (200/720)*360= 100 degrees = 1.75 Radians. - Normalized Food angle: 100-90 degrees = 1.75-1.57 Radians=0.18 Radians (By normalizing we get a measure relative to the X-axis. The actual internal angle of the sector will, of course, remain 100 degrees, since we subtract 90 degrees from the start too).
`endPoint.X` = Math.Cos(0.18) * 100 + 100 = 198 `endPoint.Y` = Math.Sin(0.18) * 100 + 100 = 117

The second `LineSegment`

joins the `endPoint`

` `back to the `centerpoint`

; thus closing the figure, which we will fill with the specified Brush for the sector. This completes the whole process of creating one Pie segment. The remaining ones are not different. They use the same calculation in a loop. The only point to be noted is that the next segment automatically starts at the end of the previous one in clockwise direction.

The following figure will further help clarify the above details:

### Data Binding

We want to bind the pie data to the `PieControl`

and `ChartControl`

objects, so that the Pie view is always updated as the data changes. In order to do so, we put the `PieSegment`

objects in an `ObservableCollection`

. Additionally we make the `PieSegment`

class implement `INotifyPropertyChanged`

interface. Whenever any property of interest changes, we receive a notification in `PieChart`

and/or `PieControl`

classes and update the view accordingly. We do this by attaching to the `PropertyChanged`

event and by recalculating and redrawing the charts whenever a change is notified.

## Conclusion

Please provide your feedback and suggestions regarding anything you think can improve the controls/article. Also if you find a bug, please let me know so that it can be removed in the next version.