How to add labels to a WPF pie chart
Update April 4 2010: The LabeledPieChart code in this post has been updated to the latest WPF and Silverlight toolkits. You can find more details in this blog post.
The WPF Toolkit and Silverlight Toolkit both include a very versatile chart control. Although support for labels (or annotations) is a frequently requested feature, it is not yet present in the current toolkits. David Anson blogged about a great solution to add labels to a ColumnSeries. In the next few posts, I will talk about one way to add labels to a PieSeries.
In this post, I will show how you can use my custom control that provides annotations for the WPF pie chart; in the next post, I will discuss the control’s implementation; and in the post after that I will show you the process of converting the WPF code to Silverlight.
Basic usage
You can use the following XAML to display a labeled pie chart with your data without any further customizations.
<customControls:LabeledPieChart
Title="Population of Puget Sound Cities"
ItemsSource="{Binding}"
IndependentValuePath="Name"
DependentValuePath="Population" />
This markup assumes that the data context is set to the following ObservableCollection:
this.cities = new ObservableCollection<City>
{
new City { Name = "Bellevue", Population = 121347 },
new City { Name = "Issaquah", Population = 23363 },
new City { Name = "Redmond", Population = 49427 },
new City { Name = "Seattle", Population = 602000 },
new City { Name = "Kirkland", Population = 47325 }
};
this.DataContext = this.cities;
Here is the result of the XAML and code above:
Label display modes
The LabeledPieChart control has four ways it can position each label:
- ArcMidpoint: The label is centered on the midpoint of the circular arc of the corresponding pie wedge.
- Connected: The label is positioned outside the pie chart, with a short line connecting it to its pie wedge.
- AutoMixed: Small pie wedges display their labels using the connected mode, and bigger wedges use the arc midpoint mode.
- Auto: If at least one pie wedge is small, all wedges use the connected mode. If all wedges are big, they all use the arc midpoint mode. Dynamically adding and removing wedges may cause all wedges to alternate between arc midpoint and connected mode.
The images below illustrate the label modes (except Auto, which looks like ArcMidpoint or Connected).
ArcMidpoint | Connected | AutoMixed |
---|---|---|
To switch between these modes, you can set the LabelDisplayMode property of the LabeledPieChart control:
<customControls:LabeledPieChart
LabelDisplayMode="Auto"
… />
Customizing the content of the labels
To configure the content of the labels, you can define a DataTemplate that displays the data you’re interested in, using the PieChartLabelItemTemplate property of LabeledPieChart:
<DataTemplate DataType="{x:Type local:City}" x:Key="pieChartLabelDataTemplate">
<Border BorderThickness="1" BorderBrush="Gray">
<StackPanel Background="White" Orientation="Horizontal">
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type customControls:PieChartLabel}}, Path=FormattedRatio}" VerticalAlignment="Center" Margin="5,0,5,0" />
<TextBlock Text="- " />
<TextBlock Text="{Binding Name}" Margin="0,0,5,0"/>
</StackPanel>
</Border>
</DataTemplate>
<customControls:LabeledPieChart
PieChartLabelItemTemplate="{StaticResource pieChartLabelDataTemplate}"
… />
The content for PieChartLabel - the custom control that displays a single label - is the actual City data item. Therefore, if you want to display properties of the data item within the label, you can bind to them by just specifying the Path.
Notice that I am using an AncestorType binding to get at the FormattedRatio property. FormattedRatio is a very handy property that gives you the percentage of the numeric value represented in the current wedge, in relation to the sum of all items. This property is defined originally on PieDataPoint, and also on PieChartLabel. PieChartLabel’s FormattedRatio is data bound to the one in PieDataPoint, so they’re kept in sync. Since the DataTemplate’s templated parent is a ContentPresenter, using TemplateBinding would try to find the FormattedRatio property on the ContentPresenter itself, which would of course fail. So, I need to keep walking up the tree to find the PieChartLabel control so that I can bind to that property. AncestorType provides an easy way of doing that.
Customizing the connector line
The connecting line’s thickness and brush are exposed as properties in PieChartLabel, and therefore can be customized easily in its style. Here’s an example:
<Style TargetType="{x:Type customControls:PieChartLabel}" x:Key="pieChartLabelStyle">
…
<Setter Property="LineStrokeThickness" Value="2"/>
<Setter Property="LineStroke" Value="Black"/>
</Style>
<customControls:LabeledPieChart
PieChartLabelStyle="{StaticResource pieChartLabelStyle}"
… />
Master-detail scenario
To implement the master-detail scenario using this chart, you simply need to set the IsSelectionEnabled property exposed by LabeledPieChart, and bind another element to the chart’s selected item:
<ContentControl Content="{Binding ElementName=labeledPieChart, Path=SelectedItem}" ContentTemplate="{StaticResource cityDetails}" />
<customControls:LabeledPieChart IsSelectionEnabled="True" x:Name="labeledPieChart" … />
Clicking on the label has the same effect as clicking on the PieDataPoint associated with it - it changes the selection of the details section.
Summary
This blog post provided a quick overview of LabeledPieChart control’s main features. Hopefully these features cover many scenarios people are looking for. However, my guess is that this code will be used as a starting point for customized scenarios. My next post discusses some implementation details, which I am hoping will inspire developers to customize and extend the control for their own needs. So stay tuned.
For more information about Charting, I recommend subscribing to David Anson’s blog - there is no better charting resource out there!
You can see this sample running as an xbap or download its source.
Jen H
Awesome. Thanks so much. j.
August 23, 2009 at 6:55 pm
ditto
Great, thanks.
How can I customize the legend? I want to add the percentage in the legend label.
August 24, 2009 at 11:23 pm
Daniel
Perfect timing. We are looking at the new WPF charting and stuck on labeling the pie charts. Thanks.
August 25, 2009 at 4:58 pm
anon
nice as usual
August 26, 2009 at 8:45 pm
denism7
Very nice and saves many hours of work. Looking forward for silverlight control that will be even more necessary.
September 7, 2009 at 5:38 am
Karsten Januszewski
Thanks Bea! I added this to The Archivist (http://flotzam.com/archivist) and it works great!
October 30, 2009 at 4:00 pm
Bea
Great to hear, Karsten!
See you next week at Oredev!
October 30, 2009 at 5:03 pm
Bea
Hi ditto,
The values in the legend come from the independent value, so you can simply change your independent values. There is no template property in Charting that allows you to customize the look of the legend items. If you look at PieSeries’ CreatePieLegendItem(…) in reflector, you will see that the content of the legend item is the independent value and that its style and template are not customizable.
Bea
November 20, 2009 at 9:59 am
Muhammad Yamin
Great, this is what I’m looking for, thanks.
January 20, 2010 at 5:46 pm
TJe.gaab
Hi
Great article. It has been working for me for months now, but I’ve just updated the toolkit. (Uninstalled the june 2009 release and installed the Feb 2010 release).
Have anyone experienced problems after installing the February 2010 WPFToolKit?
I get this error: Cannot find type ‘System.Windows.Controls.DataVisualization.StylePalette’
Any ideas how to fix it?
Best regards
Thomas
February 26, 2010 at 2:58 am
Bea
Hi Thomas,
Yes, I am aware of that. The latest versions of the toolkit introduced a breaking change that caused this solution to no longer work. I will be updating this code in a future blog post, so stay tuned!
If you need a fix for this before I’m able to get to it, you can find information about the change that is causing the break in this blog post from David.
Thanks,
Bea
March 9, 2010 at 10:40 pm