A cool feature of the xamWebChart is the ability to set an axis to use a logarithmic scale rather than a traditional linear scale. Using a logarithmic scale is useful when you have a set of data that covers a wide value range since the logarithmic scale can reduce the range to a more manageable size and result in the data being displayed in a more readable way in the chart.
To show the affects of the logarithmic scale vs the linear scale, I am going to create a chart that displays the history of the U.S. national debt. This is a good example of a dataset that covers a very wide range of values, having a low value of about 34,000 and a high value of over 10 trillion (thats 10,000,000,000,000). I’ve create a simple class called Debt to hold my data that contains a Date and a Value.
public class Debt { public Debt(double value, DateTime date) { this.Date = date; this.Value = value; } public DateTime Date { get; set; } public double Value { get; set; } }
Next, I create an ObservableCollection and populate it with a collection of Debt objects, each one containing a date representing the end of a fiscal year (starting from 1791), and a value which represents the national dept on that date. The data I am using came from U.S. Treasury’s Department of the Public Debt website.
Now I can add a chart and assign it this data and add the chart to the root of my Silverlight app.
XamWebChart chart = new XamWebChart(); Series s = new Series() { ChartType=ChartType.ScatterLine, DataMapping = "ValueX=Date;ValueY=Value", DataSource = _debt.Reverse() }; chart.Series.Add(s); this.LayoutRoot.Children.Add(chart);
Running this code results in a graph like he one shown below:
The problem is that because the debt has increased so dramatically since the late 70’s, early 80’s, those numbers are orders of magnitude larger that the debt prior to that, and by using as linear scale on the Y axis to show the debt values, data points prior to 1980 are basically lost. Using a logarithmic scale in this scenario will help me display the data which spans many orders of magnitude without losing any of its meaning.
To change the chart to use a log scale, all I have to do is define a new Y axis and set its Logarithmic property to true:
chart.Axes.Add( new Axis() { AxisType = AxisType.PrimaryY, Logarithmic = true });
Now running the sample, you can see because the chart is using a logarithmic Y axis, and its very clear that at some point in history, the U.S. has almost no national debt.
Rather than simply dividing the charts value range equally, resulting in the first tick mark being placed at 3 trillion and doubling each subsequent tick mark, the log axis calculates a log curve, placing the first tick mark at 10,000 with each subsequent tick increasing by an order of magnitude.
Now that the chart is displaying the data more clearly, I want to add some axis labels to add more context to the chart. I can use standard Silverlight layout panels in XAML to add both a Y axis label, and a chart title:
<Grid x:Name="LayoutRoot" Background="White"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition /> </Grid.RowDefinitions> <TextBlock FontSize="22" HorizontalAlignment="Center" Grid.Row="0" TextAlignment="Center"> <Run>United States National Debt</Run><LineBreak/><Run>1791 to Present</Run> </TextBlock> <Grid Grid.Row="1"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition /> </Grid.ColumnDefinitions> <TextBlock Grid.Column="0" HorizontalAlignment="Center" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Center" TextAlignment="Center"> <TextBlock.RenderTransform> <TransformGroup> <ScaleTransform/> <SkewTransform/> <RotateTransform Angle="-90"/> <TranslateTransform/> </TransformGroup> </TextBlock.RenderTransform> <Run>Debt</Run><LineBreak/><Run>(log scale)</Run> </TextBlock> <igChart:XamWebChart x:Name="xamWebChart1" Grid.Column="1" HorizontalAlignment="Stretch" Margin="0,0,0,10" /> </Grid> </Grid>
The XAML creates an 2 row outer grid with the chart title in the first row. In the second row, a 2 column grid contains both the Y-axis title (which is using a RenderTransform to rotate it 90 degrees), and the chart control.
Now all I have to do is clean up the chart a bit by providing some custom formatting to the axis tick marks and labels and adjusting the X axis range.
this.xamWebChart1.Axes.Add( new Axis() { AxisType = AxisType.PrimaryY, Logarithmic = true, AutoRange=false, Minimum=1, Maximum=100000000000000, Unit=1 }); this.xamWebChart1.Axes.Add( new Axis() { AxisType = AxisType.PrimaryX, AutoRange = false, Maximum = DateTime.Parse("1/1/2009").ToOADate(), Minimum = DateTime.Parse("1/1/1791").ToOADate(), Unit = 1500 }); this.xamWebChart1.Axes[0].Label.Format = "{0:N0}"; this.xamWebChart1.Axes[0].Label.FontSize = 11; this.xamWebChart1.Axes[0].MinorGridline = new GridlineGroup(); this.xamWebChart1.Axes[0].MinorGridline.Visibility = Visibility.Collapsed; this.xamWebChart1.Axes[1].Crossing = DateTime.Parse("1/1/1791").ToOADate(); this.xamWebChart1.Axes[1].Label.Format = "{0:yyyy}"; this.xamWebChart1.Axes[1].Label.LabelStyle = this.Resources["LabelStyle1"] as Style; this.xamWebChart1.Axes[1].MajorGridline.Visibility = Visibility.Collapsed; this.xamWebChart1.Axes[1].MajorTickMark.Unit = 400; this.xamWebChart1.Legend = new Legend(); this.xamWebChart1.Legend.Visibility = Visibility.Collapsed;
The final chart presents the data in a clear, easy to read manner, with properly formatted axis labels and informative chart titles.