Blog

Using Pie Charts in Visiblox Charts (Silverlight, WPF and Windows Phone)

In the 1.9 release of Visiblox we've added support for pie charts. This article gives an overview of these, shows basic usage and also implements an example application running on Silverlight, WP7 and WPF that uses nested pie charts.

Here's what the application looks like running on Windows Phone 7:

This article is going to cover the following:

 

Relationship Between Pie Charts and Other Series

Pie Charts are conceptually different than other series - e.g. LineSeries, ColumnSeries or BarSeries. A pie chart isn't represented in the Cartesian coordinate system, but in a special, radial coordinate system. The X axis is represented as a polar category axis, while Y values define the amount of area filled by each pie piece.

Also, while it does make sense to combine e.g. LineSeries and ColumnSeries, combining pie charts with other series or other pie series is not a clear concept.

For this reason pie charts are treated as a separate chart type and are encapsulated in the PieChart class. This results in a somewhat different API than many other charting components provide, where pie series is treated like a normal series. Our goal with this approach was to not force pie series into the Cartesian model that the Chart class represents.

Creating Pie Charts

 

Creating Pie Charts without DataBinding

Creating a pie chart only requires creating the PieChart object and adding it to the visual tree. This can be done the following way using XAML:

<UserControl (...) xmlns:charts="clr-namespace:Visiblox.Charts;assembly=Visiblox.Charts">
   <charts:PieChart x:Name="MainChart" Height="440" Width="500" Title="My Chart"/>
</UserControl>

Once the chart created, data needs to be added to it. Data is added by setting the DataSeries property on PieChart. The DataSeries is of type IDataSeries. The simplest way to set values is by creating a DataSeriesgeneric class and assigning this to the property:

MainChart.Title = "My Chart";
var dataSeries = new DataSeries<string, double>();
dataSeries.Add(new DataPoint<string,double>("Item 1",3));
dataSeries.Add(new DataPoint<string,double>("Item 2",4));
dataSeries.Add(new DataPoint<string,double>("Item 3",5));
dataSeries.Add(new DataPoint<string,double>("Item 4",2));
MainChart.DataSeries = dataSeries;

The following screenshot demonstrates the chart this code would produce:

Creating Pie Charts with DataBinding

Creating DataPoints is convenient in some situations, however when working with an existing model object and when using MVVM, this is not the desired route. Pie charts support data binding - similar to the way all other Visiblox charts can be data bound.

To bind to an existing collection, a BindableDataSeries needs to be created, its XValueBinding and YValueBindings need to be set and this object need to be assigned to the DataSeries property of PieChart. For code showing this, take a look at the example application section.

Selection on Pie Charts and Exploding Pie Charts

Pie charts are selectable, however selection is turned off by default. To enable selection, the SelectionMode property needs to be set to Single or Multiple. To enable highlighting on mouseover, the HighlightingEnabled property should be set to true.

When selecting a pie piece, by default, its border is thickened and its color is changed to a darker one. However, a bit more fancy visual effect can be achieved by setting the IsExploding property to true:

Click on both of the pie charts to see the effects in action.

The XAML for creating the above pie charts is the following:

<charts:PieChart x:Name="PieChartNonExploding" Width="300" Height="150"
       Title="Non-exploding Pie Chart" SelectionMode="Single" HighlightingEnabled="True" />
<charts:PieChart x:Name="PieChartExploding" Width="300" Height="150"
       Title="Exploding Pie Chart" SelectionMode="Multiple" HighlightingEnabled="True" IsExploding="True"/>

PieChart defines a SelectedItem property, a SelectedItems collection and a SelectionChanged event which are updated and fired similar to other Silverlight / WPF controls, such as the ListBox.

An Example Silverlight Application Using Drill-down Pie Charts

In this example we'll be creating an example where selecting a main pie chart will cause another pie chart to be animated on screen with further details on the selected item. The final application will look as follows. Click on the main pie chart to have the detail pie chart bounce in and click on the detail pie chart to show additional details:

Defining the Model

First, let's define the model that we'll be using in this example. Since we'll be creating a chart on reporting let's define a ReportItem class that has a Name, Value and can have a list of report items:

public class ReportItem
{
    public string Name { get; private set; }

    public double Value { get; private set; }

    public List<ReportItem> SubReportItems { get; private set; }

    public ReportItem(string name, double value)
        : this(name, value, new List<ReportItem>())
    {
    }
    public ReportItem(string name, double value, List<ReportItem> subSegments)
    {
        Name = name;
        Value = value;
        SubReportItems = subSegments;
    }
}

 

Creating the View

Having defined the model that we'll be using let's now define the view. We'll need a main pie chart on the screen (MainChart), a sub chart (DetailChart) and an element to show the details of the selected element (InformationContainer).

We'll be binding items both to MainChart and DetailChart thus as detailed above we'll use a BindableDataSeries to do so and set up the bindings in XAML. We'll also have selection enabled on both pie charts by setting IsInteractionEnabled to true and SelectionMode to Single. The XAML of the view is as follows:

<UserControl.Resources>
    <Style TargetType="Border" x:Key="NoPlotAreaBorder">
        <Setter Property="BorderThickness" Value="0" />
    </Style>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White" Width="800">
    <Canvas x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" Width="700" Height="400">
        <!-- The main chart -->
        <charts:PieChart x:Name="MainChart" Height="350" Width="400" 
                            Title="Annual Revenue, 2010" 
                            SelectionMode="Single" HighlightingEnabled="True"
                            IsExploding="True"
                            >
            <charts:PieChart.DataSeries>
                <charts:BindableDataSeries XValueBinding="{Binding Name}" YValueBinding="{Binding Value}" />
            </charts:PieChart.DataSeries>
        </charts:PieChart>
        <!-- The sub-chart -->
        <charts:PieChart x:Name="DetailChart" Height="200" Width="300" 
                            Canvas.Top="200" Canvas.Left="850" 
                            PlotAreaBorderStyle="{StaticResource NoPlotAreaBorder}" 
                            SelectionMode="Single" HighlightingEnabled="True">
            <charts:PieChart.DataSeries>
                <charts:BindableDataSeries XValueBinding="{Binding Name}" YValueBinding="{Binding Value}" />
            </charts:PieChart.DataSeries>
        </charts:PieChart>
        <!-- The label showing details of the selected sub-chart piece -->
        <Border Background="#630000" x:Name="InformationContainer" Visibility="Collapsed" Width="280" Height="35" 
                Canvas.Top="160" Canvas.Left="350" 
                HorizontalAlignment="Left" VerticalAlignment="Top" Padding="10,0,10,0">
            <TextBlock x:Name="TbxInfo" FontWeight="Normal" Foreground="White" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center"/>
        </Border>
    </Canvas>
</Grid>

 

Tying it All Together: Handling Selection and Updating the Drill-down Chart

In order for the sample to work, we need to populate MainChart and handle when it's selected, animating DetailChart on the view. So let's set the data source and register for the SelectionChanged event:

private List<ReportItem> _reportItems;

private ReportItem _selectedReportItem;

public MainPage()
{
    InitializeComponent();
    // Generate the model items
    _reportItems = GenerateReportItems();
    (MainChart.DataSeries as BindableDataSeries).ItemsSource = _reportItems;
    // Subscribe to SelectionChanged events
    MainChart.SelectionChanged += new SelectionChangedEventHandler(MainChart_SelectionChanged);
}

When the selection has changed on MainChart we need to populate DetailChart with the data of the selected segment and then animate it so that it bounces in from the right.

/// <summary>
/// Invoked when the SelectionChanged event is fired on MainChart
/// </summary>
void MainChart_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    // Hide the detailed chart and the label
    InformationContainer.Visibility = Visibility.Collapsed;
    Canvas.SetLeft(DetailChart, 850);

    // If an item is selected on the main chart, set the data of the detailed chart to the selected item
    var selectedSegmentReport = MainChart.SelectedItem as ReportItem;
    if (selectedSegmentReport != null)
    {
        _selectedReportItem = selectedSegmentReport;
        // Set the data source of the detailed chart to the details of the selected item
        (DetailChart.DataSeries as BindableDataSeries).ItemsSource = _selectedReportItem.SubReportItems;
        AnimateDetailedChart();
    }
}

/// <summary>
/// Animates the detail pie chart to bounce in from the right.
/// </summary>
private void AnimateDetailedChart()
{
    var da = new DoubleAnimation();
    da.Duration = new Duration(TimeSpan.FromSeconds(1.4));
    Storyboard.SetTarget(da, DetailChart);
    Storyboard.SetTargetProperty(da, new PropertyPath("(Canvas.Left)"));
    da.To = 320;
    da.EasingFunction = new ElasticEase() { EasingMode = EasingMode.EaseOut, Springiness = 5 };
    var sb = new Storyboard();
    sb.Children.Add(da);
    sb.Begin();
}

The last part of the example is handling the selection on the DetailChart so when it's clicked, text shows up showing details on the selected item.

To do so we need to register to the SelectionChanged event of the chart in the constructor:

public MainPage()
{
    InitializeComponent();
    (...)
    DetailChart.SelectionChanged += new SelectionChangedEventHandler(DetailChart_SelectionChanged);
}

When the selection has changed, in the change handler we simply display further information on the red panel by setting its Text property and visibility accordingly:

void DetailChart_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var selectedSubReportItem = DetailChart.SelectedItem as ReportItem;
    if (_selectedReportItem != null && selectedSubReportItem != null)
    {
        InformationContainer.Visibility = Visibility.Visible;
        TbxInfo.Text = String.Format("{0} - {1}: ${2}M",_selectedReportItem.Name, selectedSubReportItem.Name, selectedSubReportItem.Value);
    }
    else
    {
        InformationContainer.Visibility = Visibility.Collapsed;
    }
}

 

Download the Code

The source code for the Silverlight example can be downloaded from here: Visiblox Charts for Silverlight - Pie Charts.zip. To compile it, download the latest version of Visiblox Charts and add the Visiblox Silverlight dll as a reference to the project.

Example Pie Chart Application in WPF

The example can easily be ported to WPF as the pie chart API is identical to the one in Silverlight. The only thing that needs to be changed is the surroundings parts of the XAML (as WPF has a Windows object containing the application), all other parts of the code are exactly the same.

The final application is also identical in behaviour to the Silverlight one, here's a screenshot of it:

The WPF example can be downloaded from here: Visiblox Charts for WPF - Pie Charts.zip. To compile it, download the latest version of Visiblox Charts and add the Visiblox Charts WPF dll as a reference to the project.

Example Pie Chart Application on Windows Phone 7

The example can also easily be ported to WP7 where the pie chart API is identical to the one in Silverlight 4. The only thing that needs to be slightly changed is the view of the application as the phone requires a bit of different layout. The code behind of the application, however can be reused, keeping the same logic.

The final application is also identical in behaviour to the Silverlight one, here's a screenshot of it:

You can download the code of the example from here: Visiblox Charts for Windows Phone 7 - Pie Charts. To compile it you need to download and install Silverlight Toolkit for Windows Phone as well as the latest version of Visiblox Charts and reference the WP7 Visiblox.Charts.dll in the project.

Summary

This blog post gave a quick overview of how to use the pie chart API in Visiblox Charts for Silverlight, WPF and Windows Phone 7. It also walked through the development of an example application implementing nested pie charts in Silverlight. Almost all of the Silverlight code was then reused when porting the same example to WPF and Windows Phone 7.

If you want to try it out for yourself, why not download the free version of Visiblox Charts - which has support for pie charts - and give it a go?

Comments

What am I missing with a pie chart? (I'm using the trial version.) The Visiblox logo shows up but the chart is not created and/or visible. In my view model, I have the following:

public ObservableCollection AgentStatusSummary { get { var result = new ObservableCollection(); result.Add(new ChartData() { Status = "Logged out", Percent = 3d }); result.Add(new ChartData() { Status = "Unavailable", Percent = 3d }); result.Add(new ChartData() { Status = "Available", Percent = 1d }); return result; } }

and in XAML I have tried the following variations:

...or...

Thanks.

 
Posted by Tim

Sorry - the XAML that I included in my last post did not get accepted. Here's another attempt at adding it: <charts:PieChart Grid.Row="4" Grid.ColumnSpan="2" Name="AgentStatus"                    DataContext="{Binding Source={StaticResource agentMonitorVmViewSource},                                   Path=AgentStatusSummary}" Title="Agent Status" HorizontalContentAlignment="Center" IsExploding="False" AnimationEnabled="False" Height="200"                   Width="300" > <charts:PieChart.DataSeries>                   <charts:BindableDataSeries ItemsSource="{Binding}" /> </charts:PieChart.DataSeries></charts:PieChart> ...or... <charts:PieChart Grid.Row="4" Grid.ColumnSpan="2" Name="AgentStatus"                    DataContext="{Binding Source={StaticResource agentMonitorVmViewSource},                                   Path=AgentStatusSummary}" Title="Agent Status" HorizontalContentAlignment="Center" IsExploding="False" AnimationEnabled="False" Height="200"                   Width="300" > <charts:PieChart.DataSeries>                   <charts:BindableDataSeries XValueBinding="{Binding Status}"    YValueBinding="{Binding Percent}"/> </charts:PieChart.DataSeries></charts:PieChart>

 
Posted by Tim

Hi Tim,

What you need to do it to set the DataContext to agentMonitorViewSource instead of binding to it and also bind the BindableDataSeries.ItemsSource to AgentStatusSummary (which is the collection of ChartData items). In other words:

<charts:PieChart Name="AgentStatus" DataContext="{StaticResource agentMonitorVmViewSource}" Title="Agent Status" HorizontalContentAlignment="Center" IsExploding="False" AnimationEnabled="False" Height="200" Width="300" > <charts:PieChart.DataSeries> <charts:BindableDataSeries ItemsSource="{Binding AgentStatusSummary}" XValueBinding="{Binding Status}" YValueBinding="{Binding Percent}"/> </charts:PieChart.DataSeries> </charts:PieChart>

I hope that helps!

 
Posted by Effrosyni Kouri
Hi is it possible to predefine colors in the pie chart ? or even better have it databinded Ivar
 
Posted by Ivar
Hi Ivar,
You could set the Palette property of the PieChart to a SimplePalette instance, in xaml that would look something like: <charts:SimplePalette StyleTemplates="{StaticResource DefaultPieChartStyleTemplates}" Colors="#FFCF3B37,#FF0C0F0F,#FF60B167,..." />
The Colors string contains a comma-separated list of RGBA values. You can find DefaultPieChartStyleTemplates in the generic.xaml file that came with the component.
The Palette property could also be bound to a property in the ViewModel, possibly using an appropriate Converter.
Is that what you were looking for?
Regards,
Partha
 
Posted by Partha

Post a comment