Title: Draw a labeled pie chart in C#
The example Draw a pie chart in C# shows how to draw a simple pie chart. This example adds labels to the pie slices.
This example uses the following code to draw its pie chart.
// Draw the pie chart.
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(BackColor);
if ((ClientSize.Width < 20) || (ClientSize.Height < 20))
return;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
Rectangle rect = new Rectangle(
10, 10, ClientSize.Width - 20, ClientSize.Height - 20);
DrawLabeledPieChart(e.Graphics, rect, -90, SliceBrushes,
SlicePens, Values, "0.0", Font, Brushes.Black);
}
// Draw a pie chart.
private static void DrawLabeledPieChart(Graphics gr,
Rectangle rect, float initial_angle, Brush[] brushes,
Pen[] pens, float[] values, string label_format,
Font label_font, Brush label_brush)
{
// Get the total of all angles.
float total = values.Sum();
// Draw the slices.
float start_angle = initial_angle;
for (int i = 0; i < values.Length; i++)
{
float sweep_angle = values[i] * 360f / total;
// Fill and outline the pie slice.
gr.FillPie(brushes[i % brushes.Length],
rect, start_angle, sweep_angle);
gr.DrawPie(pens[i % pens.Length],
rect, start_angle, sweep_angle);
start_angle += sweep_angle;
}
// Label the slices.
// We label the slices after drawing them all so one
// slice doesn't cover the label on another very thin slice.
using (StringFormat string_format = new StringFormat())
{
// Center text.
string_format.Alignment = StringAlignment.Center;
string_format.LineAlignment = StringAlignment.Center;
// Find the center of the rectangle.
float cx = (rect.Left + rect.Right) / 2f;
float cy = (rect.Top + rect.Bottom) / 2f;
// Place the label about 2/3 of the way out to the edge.
float radius = (rect.Width + rect.Height) / 2f * 0.33f;
start_angle = initial_angle;
for (int i = 0; i < values.Length; i++)
{
float sweep_angle = values[i] * 360f / total;
// Label the slice.
double label_angle =
Math.PI * (start_angle + sweep_angle / 2f) / 180f;
float x = cx + (float)(radius * Math.Cos(label_angle));
float y = cy + (float)(radius * Math.Sin(label_angle));
gr.DrawString(values[i].ToString(label_format),
label_font, label_brush, x, y, string_format);
start_angle += sweep_angle;
}
}
}
The first part of the code is similar to the previous example. The second part draws the labels on the slices. The code labels the slices after drawing all of them, as opposed to labeling each slice as it is drawn, so a slice won't cover up the label of a previously drawn very thin slice.
The labeling code makes a StringFormat object and prepares it to center text. It then finds the center of the rectangle containing the pie chart.
Next the code calculates a radius along which to draw slice labels. To get this radius, the code averages the chart's width and height, and multiplies by 0.33. That makes the radius about 2/3 of the rectangle's half-width/height. If the rectangle is square, then the pie chart is circular and this radius really is 2/3 of the circle's radius.
The code then loops through the slice angles much as it did when drawing the slices. This time it calculates the angle in the middle of each slice and uses sines and cosines to find the point that is distance radius from the center to the edge of the pie chart along that angle. It then draws the label centered at that position.
Download the example to experiment with it and to see additional details.
|