Pie Chart Easy AS…. - Jesse Liberty - Silverlight Geek Page view counter

Pie Chart Easy AS….

I wanted to add an animated pie chart to my previous post.  The samples from the Toolkit are terrific, but sometimes it is difficult to find the easiest, most cookbook like process; so for those of you who might want to do the same, here is an annotated walk-through of creating this animated pie chart:

I began by opening Visual Studio and creating a new Silverlight Application, and saying no to the offer to create a Web application.

The UI, created in Page.xaml consists of the header and the Chart, placed in a Grid. You can easily do this in Blend or, in this case the layout is so simple, I hard-coded it in Xaml:

<UserControl 
xmlns:chartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;
assembly=System.Windows.Controls.DataVisualization.Toolkit"

x:Class="Pi.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="350" Height="350">
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>



<TextBlock Text="Division of Effort Among Activities"
Margin="20,10,0,0"
Grid.Row="0"
FontFamily="Georgia"
FontSize="18"
Foreground="Blue" />

<chartingToolkit:Chart x:Name="ActivityChart"
Margin="20"
Grid.Row="1">
<chartingToolkit:Chart.Series>
<chartingToolkit:PieSeries Title="Fall Activity"
IndependentValueBinding="{Binding Name}"
DependentValueBinding="{Binding Value}" />
</chartingToolkit:Chart.Series>
</chartingToolkit:Chart>

    </Grid>
</UserControl>

The key Xaml here is the Chart control which contains a Series which in turn contains a PieSeries. The PieSeries has an Independent and a Dependent set of values, as explained in some detail here.

To have a set of values to bind to, I created a data class that I named Activity. The Activity class has three properties of interest:

  • Name – used to hold the independent value
  • Value – used to hold the dependent value
  • Activities – returns a list of Activity objects
   1: using System;
   2: using System.Collections.Generic;
   3:  
   4: namespace Pi
   5: {
   6:   public class Activity
   7:   {
   8:     public string Name { get; set; }
   9:     public double Value { get; set; }
  10:     
  11:     // static property to retrieve 
  12:     // List of Activity objects
  13:     public static List<Activity> Activities
  14:     {
  15:       get
  16:       {
  17:         // value of 5 and names of activities are hard coded
  18:         // Generalizing is left as an exercise for the ambitious
  19:         var percentages = FillPercentages(5);  
  20:         var activitiesList = new List<Activity>()
  21:              {
  22:                new Activity() {Name = "RiaServices", Value = percentages[0]},
  23:                new Activity() {Name = "DataGrid", Value = percentages[1]},
  24:                new Activity() {Name = "Behaviors", Value = percentages[2]},
  25:                new Activity() {Name = "VSM", Value = percentages[3]},
  26:                new Activity() {Name = "SampleData", Value = percentages[4]}
  27:              };
  28:         return activitiesList;
  29:       }
  30:     }
  31:  
  32:     // fill List<Double> with n doubles that sum to 1.0
  33:     // where n = numDoubles
  34:     private static List<Double> FillPercentages(int numDoubles)
  35:     {
  36:       var pctgs = new List< Double >();
  37:       var r = new Random();
  38:       double total = 0.0;
  39:       
  40:       for (int i = 0; i < numDoubles-1;)
  41:       {
  42:  
  43:         double val = r.NextDouble();
  44:         if ( val + total < 1.0)
  45:         {
  46:           pctgs.Add(val);
  47:           ++i;
  48:         }
  49:       }
  50:       pctgs.Add( 1.0 - total );  // final value
  51:       return pctgs;
  52:     } 
  53:  
  54:   }   // end class
  55: }     // end namespace

On line 13 we start the definition of the Activities property (only a get accessor is implemented)

On line 19 we delegate to a helper method generating 5 random values between 0 and 1 that together sum to 1. These will be treated as the relative percentages reflected in the pie chart.

Lines 20-27 fill our five hard-coded activities with the generated percentages and on line 28 we return the List of Activity objects we just created.

The code-behind for MainPage uses a dispatch timer to call a helper method FillPie every 4 seconds.

The helper method sets the ItemSource property on the PieSeries to whatever is returned by the static Activities property of the Activity class. Retrieving that property causes the percentages to be regenerated, and the chart is redrawn.

 

   1: using System;
   2: using System.Windows.Controls;
   3: using System.Windows.Controls.DataVisualization.Charting;
   4: using System.Windows.Threading;
   5:  
   6: namespace Pi
   7: {
   8:   public partial class MainPage : UserControl
   9:   {
  10:     public MainPage()
  11:     {
  12:       InitializeComponent();
  13:       Animate();
  14:     }
  15:  
  16:     private void Animate()
  17:     {
  18:       var timer = new DispatcherTimer();
  19:       timer.Start();  // Run once for display
  20:       // lambda syntax - same as
  21:       // timer.Tick +=new EventHandler(FillPie);
  22:       // but then you'd need FillPie to take an object and event args
  23:       timer.Tick +=
  24:           ( ( s, args ) => FillPie() );  // every tick call FillPie
  25:  
  26:       // http://msdn.microsoft.com/en-us/library/cc316852.aspx
  27:       timer.Interval = new TimeSpan( 0, 0, 4 ); // 4 seconds
  28:       timer.Start();
  29:     }
  30:  
  31:  
  32:     private void FillPie()
  33:     {
  34:       var cs = ActivityChart.Series[0] as PieSeries;
  35:       if ( cs != null )
  36:       {
  37:         // generating the data is handled by the static property
  38:         cs.ItemsSource = Activity.Activities;
  39:       }
  40:       else
  41:       {
  42:         throw new InvalidCastException( "Expected Series[0] to be a column" );
  43:       }  // end else
  44:     }    // end method
  45:   }      // end class
  46: }        // end namespace

Notice that on lines 23 and 24 we register the FillPie method with the event using lambda notation; this makes short work of using a method that does not happen to need the standard arguments (object, eventArgs).

Timer.Start is called on line 19 to cause an immediate drawing of the pie, and then again on line 28 to implement the new time interval.

Published Thursday, August 27, 2009 2:33 PM by jesseliberty
Filed under: ,

Comments

# OK, So Now Where’s Jesse??

Like many other developers before me, I’ve been hit with a pretty bad case of Carpal Tunnel. Expected

Thursday, August 27, 2009 2:57 PM by Microsoft Weblogs

# Twitter Trackbacks for Pie Chart Easy AS???. - Jesse Liberty - Silverlight Geek [silverlight.net] on Topsy.com

Pingback from  Twitter Trackbacks for                 Pie Chart Easy AS???. - Jesse Liberty - Silverlight Geek         [silverlight.net]        on Topsy.com

# re: Pie Chart Easy AS….

I think you have a memory leak in your silverlight example...

I left this page open in my browser overnight and by the next morning, this IE process was consuming almost 450 MB of memory and was unresponsive to the UI input.

I am running Silverlight 3.0.40723.0 and IE 8.0.7600.16385.

Wednesday, September 02, 2009 9:26 AM by drhender