Line Chart in Silverlight with Two Legends, Scatters and Custom Labels

In this post we are discussing how to build a line chart with multiple series, scatters in custom colors,
two legends and custom labels at the X-axis. We are building the chart in Silverlight, using the
MindFusion.Charting for Silverlight tool.

Data

The data for the chart is taken from an ObservableCollection, where each member represents sales for a
given month.

lineChart1.DataSource = sales;

The Axes

The Y-axis shows an auto scale. This is the default LabelType so we don’t need to change it. But we want custom title label and intervals of 100. Here is how we set this:

lineChart1.YAxisSettings.Interval = 100L;
lineChart1.YAxisSettings.TitleOffset = 10.0;
lineChart1.YAxisSettings.Title = "USD";

The X-axis requires more customization. We want to show custom labels, that’s why we must set them and change the LabelType to show them:

lineChart1.XAxisSettings.LabelType = LabelType.CustomText;
lineChart1.XAxisSettings.CustomLabelPosition = CustomLabelPosition.ChartDataPoints;

We use the XLabelPath property to bind the Month field in our DataSource to the X-labels of the chart. We also set the maximum value at the X-axis and draw pointers to the labels by setting the Tick property.


lineChart1.XAxisSettings.MaxValue = sales.Count + 1;
lineChart1.XAxisSettings.Tick = 5.0;

The Series

The data for each series comes from a specific field in the DataSource collection:

lSeries1.YDataPath = "Turnover";
lSeries2.YDataPath = "Profit";

We want to show scatters and we use the ScatterType property to set the type. By default the type is “None” and no scatters are drawn. We need to change that:

lSeries1.ScatterType = ScatterType.Diamond;
lSeries1.ScatterSize = 20;

The brushes for the scatters are set with a BrushCollection:

BrushCollection sBrushes1 = new BrushCollection();
sBrushes1.Add(new SolidColorBrush(Colors.Red));
sBrushes1.Add(new SolidColorBrush(Colors.Red));
sBrushes1.Add(new SolidColorBrush(Colors.Yellow));
sBrushes1.Add(new SolidColorBrush(Colors.Green));


lSeries1.ScatterFills = sBrushes1;

Finally, don’t forget to add your LineSeries to the chart:

lineChart1.Series.Add(lSeries1);
lineChart1.Series.Add(lSeries2);

Legends

In this chart we need two legends – one is for the scatters and one for the series. They are both of
type SeriesLegend, which gives us control over the brushes and labels used.

The legend for the scatters is docked to the bottom and is aligned in the center.

MindFusion.Charting.Silverlight.SeriesLegend legend =
new MindFusion.Charting.Silverlight.SeriesLegend();
legend.LabelsSource = new List() { "Higher than expected", "Lower than expected", "Meets expectations"};
legend.BorderBrush = new SolidColorBrush(Colors.LightGray);
LayoutPanel.SetDock(legend, Dock.Bottom);
legend.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;

Here is how we set the brushes:

BrushCollection brushes = new BrushCollection();
brushes.Add(new SolidColorBrush(Colors.Green));
brushes.Add(new SolidColorBrush(Colors.Red));
brushes.Add(new SolidColorBrush(Colors.Yellow));
legend.BrushesSource = brushes;
lineChart1.Legends.Add(legend);

The code for the other legend is similar, but we dock it to the right and align it to the top:

LayoutPanel.SetDock(sLegend, Dock.Right);
sLegend.VerticalAlignment = System.Windows.VerticalAlignment.Top;

Finally, don’t forget to add the two legends to the chart:

lineChart1.Legends.Add(legend);
lineChart1.Legends.Add(sLegend);

Here is the final result:

Line chart with scatters, two legends and custom labels. The platform is Silverlight.

Line chart with scatters, two legends and custom labels. The platform is Silverlight.

The source code is available for download from here:

Download the Complete Source Code for the Sample

You can get the trial version of MindFusion.Charting for Silverlight from this link:

Download MindFusion.Charting for Silverlight Trial Version

Drill Down Chart in WPF

In this post we discuss how to create a drill down chart with the MindFusion.Charting for WPF tool. Our main chart will be a pie chart, where each peace shows some aggregate data. When clicked, a new chart pops up – a bar chart, which shows details about the clicked piece.

The Data

For the data we use an ObservableCollection called CompanyExpenses. It contains objects of type Expenses. The Expenses class implements INotifyPropertyChanged. Here is a code snippet:

public class Expenses : INotifyPropertyChanged
    {
  public Expenses(string corporationName, double marketing, double salaries, 
            double rawMaterials, double logistics, double administration, double production)
        {
            this.corporationName = corporationName;
            this.marketing = marketing;
            this.salaries = salaries;
            this.rawMaterials = rawMaterials;
            this.logistics = logistics;
            this.administration = administration;
            this.production = production;
          
}

.............
}  

We have properties for the various company expenses and a property for the name of the corporation. We have a special Sum property, which gives us the total of all expenses for the corporation. This property will be used by the main chart – the pie chart:

public double Sum
        {
            get { return sum; }
            set
            {
                sum = value;
                OnPropertyChanged("Sum");
            }
        }

The Pie Chart

The pie chart displays the expenses of all 5 corporations – together with their name and their share. We use data binding, the ComapnyExpenses list provides the DataSource:

CompanyExpenses data = new CompanyExpenses();
 pieChart1.DataSource = data;

In order to show the name of the company as an outer label, we must set the OuterLabelType to CustomText and bind Expenses.CorporationName to the OuterLabelPath property. We do this in XAML:

my:PieSeries OuterLabelOffset="30" OuterLabelPath="CorporationName" OuterLabelType="CustomText" DataPath="Sum" InnerLabelType="Percents" Name="pieSeries1" DetachedPiecesList="20"

The Sum property, which we mentioned above, provides data for the chart. The brushes are set with the brush editor in the property grid.

Hit Testing

We use the charting component’s HitTest method to detect when a piece was clicked and to show a bar chart with the respective data. PiePiece.PieceIndex gives us the index of the clicked piece. We use the Control.MouseDown event to detect mouse clicks.

private void pieChart1_MouseDown(object sender, MouseButtonEventArgs e)
        {
            List result = 
                pieChart1.HitTest(e.GetPosition(pieChart1));

            if (result.Count > 0 && result[0] is MindFusion.Charting.Wpf.PiePiece)
            {
                MindFusion.Charting.Wpf.PiePiece piece = 
                    result[0] as MindFusion.Charting.Wpf.PiePiece;

                Details d = new Details(data[piece.PieceIndex]);
                d.Show();
            }
        }

The HitTest method returns a collection of ChartElement objects. In our case we don’t have several ChartElements that overlap each other and might be clicked simultaneously, that’s why we take the first ChartElement.

The Detailed Chart

The detailed chart is a bar chart that displays the data for a single Expenses object. We set the labels at the X-axis to display the type of the expense:

barChart1.XAxisSettings.LabelType = MindFusion.Charting.Wpf.LabelType.CustomText;
            barChart1.XLabels = new List() { "Marketing", "Salaries", "Raw Materials", "Logistics", "Administration", "Production"};
            barChart1.XAxisSettings.LabelRotationAngle = 30;
            barChart1.XAxisSettings.CustomLabelPosition = MindFusion.Charting.Wpf.CustomLabelPosition.ChartDataPoints;

When we create the Details window, we pass as argument the Expenses object the chart refers to:

public Details( Expenses expenses)
{
barSeries1.YData = expenses.ExpensesList;

}

The data for the bar chart comes from the list of the expenses, which is a DoubleCollection.

Here is a screenshot of the final drill down chart:

The main pie chart with the bar chart that shows details for the clicked pie piece.

The main pie chart with the bar chart that shows details for the clicked pie piece.

You can download the complete source code for the project from this link:

Download MindFusion.Charting Drill Down Sample

Charting for WPF 1.8

MindFusion has released a new version of its Charting component for Wpf with the following new features:

Styles and Themes
Styles define the appearance of individual chart elements such as the axis, the series and the legend. Each ChartTheme contains a collection of styles and defines the appearance of the whole chart. The new version lets you:

  • create themes based on the appearance of an existing chart;
  • create themes with the ThemeEditor tool;
  • save themes to XML files;
  • load themes from XML files;
  • use a number of predefined themes.

The “Working with Themes” tutorial gives detailed information on how to create, save, load and edit themes with MindFusion.Charting for WPF.

The green theme

The green theme

Improved Design Time Support
You can now edit all collection properties, including the Series collection, the brushes and strokes in design time through the property grid.

Axis Intervals
The new AxisSettings.IntervalCount property lets you specify the exact number of intervals at the axis. In such case, the control does not use the Interval property and calculates the value of each interval based on AxisSettings.Min, AxisSettings.Max and AxisSettings.IntervalCount properties.

You can read further details about the release and the other new features at the news section in the Charting forum. A trial version is available for download from here:

Download MindFusion.Charting for WPF 1.8 Trial Version

You are welcome to contact us with any questions, problems or inquiries about the Charting for Wpf control or any other of our products. MindFusion has always put special emphasis on providing excellent customer support and we usually answer your inquiries in a few hours of receiving them.

About MindFusion.Charting for Wpf: A programming component that combines powerful charting capabilities with an elegant API and easy use. Among the features of the control are fully customizable grid, positive and negative values on all chart axes, 3D charts, gauges and many more – read a detailed list here.

The control provides detailed documentation and various samples that demonstrate how to customize every type of chart. It supports a wide range of 2D and 3D charts including bar, line, radar, bubble pie etc. You can add tooltips, define themes, perform hit testing, zoom and more.

Real Time Line Chart

In today’s post we are going to build a real time line chart with the following features:

  • 8 data series with 100 points each.
  • Ten times per second we add 10 random points to each series and remove the last ten.
  • Each tenth of the second we update the min and max values of the X-axis.
  • Legend
The final chart

The final chart

Create the series

We create 8 series and add them to the Series collection of the chart:

for (int i = 0; i < 8; i++)
{
     LineSeries series = new LineSeries();
     series.StrokeThickness = 3;
     series.Strokes.Add(RandomStroke);
     series.Fills = series.Strokes;
     series.Title = "Series" + i;
     series.XData = new DoubleCollection();
     series.YData = new DoubleCollection();

     for (int j = 0; j < 100; j++)
     {
        series.XData.Add(j);
        series.YData.Add(10 + 10 * i + random.Next(-5, 5));
      }

     lineChart.Series.Add(series);
 }

Each series is drawn with a random generated stroke:

  private Brush RandomStroke
  {
     get
     {
        byte r = (byte)random.Next(0, 255);
        byte g = (byte)random.Next(0, 255);
        byte b = (byte)random.Next(0, 255);
        return new SolidColorBrush(Color.FromArgb(255, r, g, b));
       }
     }

We must set the Title and Fills properties though we don’t need them for the chart – they are used by the legend. The Y-values of the line points are random numbers between 10 and 90.

The Legend

ChartLegend legend = new ChartLegend();
legend.Series = lineChart.Series;
lineChart.Legends.Add(legend);

Our legend is of type ChartLegend, which means we must set its Series property to the list of ChartSeries that the legend explains. The ChartLegend reads the labels for its items from the Title property of a ChartSeries. It draws the series rectangles with the first brush in ChartSeries.Strokes and fills them with the first brush in ChartSeries.Fills. That’s why it was important to set the Title, Fills and Strokes properties as shown above.

The Axis
The axis shows scale divisions with interval 10. Initially they range from 0 to 100 in 10 intervals.

lineChart.XAxisSettings.MinValue = 0;
lineChart.XAxisSettings.Interval = 10;
lineChart.XAxisSettings.LabelType = LabelType.AutoScale;

Updating Data in Real Time

We create a timer that simulates reading real time data. The timer ticks ten times every second:

timer.Interval = TimeSpan.FromMilliseconds(100);
timer.Tick += new EventHandler(OnTimerTick);

When the timer ticks, we generate ten new values for each of the eight series, add them to each series and remove the last ten values:

foreach (LineSeries series in lineChart.Series)
{
    for (int i = 10 - 1; i >= 0; i--)
    {
         series.XData.Remove(series.XData[i]);
         series.YData.Remove(series.YData[i]);
    }
}

foreach (LineSeries series in lineChart.Series)
{
    int counter = 0;
    for (int i = 0; i < 10; i++)
    {
         series.XData.Add(i + maxX);
         series.YData.Add(10 + counter * 10 + random.Next(-5, 5));
     }
     counter++;
}

Here we use a global variable maxX, which we have declared in the class:

private int maxX = 100;

We increase our global variable with 10 to keep up with the change in the data:

maxX += 10;

Updating the Axis
At each tick of the timer we increase the start of the axis with 10:

lineChart.XAxisSettings.MinValue += 10;

Performance Optimization
Performance is greatly improved if we set the thickness of the lines to 1 rather than 3. The reason for this is that Windows GDI system draws thick lines by filling polygons. This requires numerous calculations about the coordinates of each polygon. When the thickness is small, Windows GDI draws lines rather than polygons, which speeds up drawing and performance.

series.StrokeThickness = 3;

Download of the Sample
You can download the sample with complete source code from here:

Download the Sample