Time-series charts display time along the X-axis. This is a very common type of chart, used to show how values change as time passes.
Most time-series charts show constant time intervals (yearly, monthly, weekly, daily). In this case, the time-series chart is essentially identical to a simple value type chart like the one described above. The only difference is that instead of showing categories along the X axis, the chart will show dates or times. (If the time intervals are not constant, then the chart becomes an XY chart, described in the next section.)
Before we can create any charts, we need to generate the data that will be shown as a chart. Here is some code to create the data we need.
Note: There is nothing chart-specific in this code, this is just some generic data. We will use this data to create the Time Series and XY charts as well in the next topics.
•C#
TextBlock CreateTextBlock(string text, double fontSize, FontWeight fontWeight)
{
var tb = new TextBlock();
tb.Text = text;
tb.FontSize = fontSize;
tb.FontWeight = fontWeight;
return tb;
}
// Simple class to hold dummy sales data
public class SalesRecord
{
// Properties
public string Region { get; set; }
public string Product { get; set; }
public DateTime Date { get; set; }
public double Revenue { get; set; }
public double Expense { get; set; }
public double Profit { get { return Revenue - Expense; } }
// Constructor 1
public SalesRecord(string region, double revenue, double expense)
{
Region = region;
Revenue = revenue;
Expense = expense;
}
// Constructor 2
public SalesRecord(DateTime month, string product, double revenue, double expense)
{
Date = month;
Product = product;
Revenue = revenue;
Expense = expense;
}
}
// Return a list with one SalesRecord for each region
List<SalesRecord> GetSalesPerRegionData()
{
var data = new List<SalesRecord>();
Random rnd = new Random(0);
foreach (string region in "North,East,West,South".Split(','))
{
data.Add(new SalesRecord(region, 100 + rnd.Next(1500), rnd.Next(500)));
}
return data;
}
// Return a list with one SalesRecord for each product,// Over a period of 12 months
List<SalesRecord> GetSalesPerMonthData()
{
var data = new List<SalesRecord>();
Random rnd = new Random(0);
string[] products = new string[] {"Widgets", "Gadgets", "Sprockets" };
for (int i = 0; i < 12; i++)
{
foreach (string product in products)
{
data.Add(new SalesRecord(
DateTime.Today.AddMonths(i - 24),
product,
rnd.NextDouble() * 1000 * i,
rnd.NextDouble() * 1000 * i));
}
}
return data;
}
Note that the SalesData class is public. This is required for data-binding.
We will now walk through the creation of some time-series charts.
Step 1) Choose the chart type:
The code clears any existing series, then sets the chart type:
•C#
public MainPage()
{
InitializeComponent();
// Clear current chart
c1Chart1.Reset(true);
// Set chart type
c1Chart1.ChartType = ChartType.Column;
}
Step 2) Set up the axes:
We will
start by obtaining references to both axes, as in the previous sample. Recall
that the Bar chart type uses reversed axes (values are displayed on the Y
axis):
•C#
//Get axes
Axis valueAxis = c1Chart1.View.AxisY;
Axis labelAxis = c1Chart1.View.AxisX;
if (c1Chart1.ChartType == ChartType.Bar)
{
valueAxis = c1Chart1.View.AxisX;
labelAxis = c1Chart1.View.AxisY;
}
Next we will assign titles to the axes. The axis titles are UIElement objects rather than simple text. This We will set up the axis titles using the CreateTextBlock method, the same way we did before. We will also set up the annotation format, minimum value, and major unit. The only difference is we will use a larger interval for the tick marks between values:
•C#
// configure label axis
labelAxis.Title = CreateTextBlock("Date", 16, FontWeights.Bold);
labelAxis.AnnoFormat = "M-yy";
labelAxis.FontSize = 12;
// configure value axis
valueAxis.Title = CreateTextBlock("Amount ($1000)", 16, FontWeights.Bold);
valueAxis.AnnoFormat = "#,##0 ";
valueAxis.MajorUnit = 1000;
valueAxis.FontSize = 14;
valueAxis.AutoMin = false;
valueAxis.Min = 0;
Step 3) Add one or more
data series
This time, we
will use the second data-provider method defined earlier:
•C#
// get the data
var data = GetSalesPerMonthData();
Next, we want to display the dates along the label axis. To do this, we will use a Linq statement that retrieves the distinct Date values in our data records. The result is then converted to an array and assigned to the ItemsSource property of the label axis.
•C#
c1Chart1.Data.ItemNames = (from r in data select r.Date.ToString("M-yy")).Distinct().ToArray();
Note that we used the Distinct LINQ operator to remove duplicate date values. That is necessary because our data contains one record per product for each date.
Now we are ready to create the actual DataSeries objects that will be added to the chart. Each series will show the revenue for a given product. This can be done with a Linq statement that is slightly more elaborate than what we used before, but provides a good practical example of the power provided by Linq:
•C#
// add one series (revenue) per product
var products = (from p in data select p.Product).Distinct();
foreach (string product in products)
{
var ds = new DataSeries();
ds.Label = product;
ds.ValuesSource = (
from r in data
where r.Product == product
select r.Revenue).ToArray();
c1Chart1.Data.Children.Add(ds);
}
The code starts by building a list of products in the data source. Next, it creates one DataSeries for each product. The label of the data series is simply the product name. The actual data is obtained by filtering the records that belong to the current product and retrieving their Revenue property. The result is assigned to the ValuesSource property of the data series as before.
This concludes the code that generates our time-series charts. You can test it by running it and changing the ChartType property to Bar, Column, AreaStacked, or Pie to create charts of different types. You would probably never display a time-series chart as a pie. The pie chart completely masks the growth trend that is clearly visible in the other charts.