Fixing jqPlot chart to toggle (show and hide) slices in Pie charts.

I found a question on stackoverflow where one guy found out that the enhancedLegendRenderer plugin didn’t work with jqPlot Pie Charts. He also posted a jsFiddle example where you can show/hide lines in the Line chart by clicking on legend items, but it doesn’t work with the Pie chart. I decided to investigate why it happens.

By looking at jqPlot source code I found out that the EnhancedLegendRenderer generates items 1:1 to chart series.

    if (idx < series.length) {
        s = series[idx];

Let’s look at the example. The Line chart with 6 lines has 6 series (series.length = 6).

data.push([[1,1.0] , [2,6.0] , [3,9.0] , [4,8.0]]); // #1
data.push([[1,4.0] , [2,3.0] , [3,1.0] , [4,2.0]]); // #2
data.push([[1,6.0] , [2,2.0] , [3,4.0] , [4,1.0]]); // #3
data.push([[1,1.0] , [2,2.0] , [3,3.0] , [4,4.0]]); // #4
data.push([[1,4.0] , [2,3.0] , [3,2.0] , [4,1.0]]); // #5
data.push([[1,8.0] , [2,2.0] , [3,6.0] , [4,3.0]]); // #6

But the Pie chart has only 1 series (series.length = 1).

[['Sony',7], ['Samsung',13.3], ['LG',14.7], ['Vizio',5.2], ['Insignia', 1.2]]; // #1

The EnhancedLegendRenderer would generate only 1 item for the Pie chart. This wouldn’t look good,and jqPlot automatically disabled EnhancedLegendRenderer and applied PieLegendRenderer instead which doesn’t have much functionality.

I rewrote this renderer for Pie charts and called it EnhancedPieLegendRenderer. Here is the final result:

jqplot pie chart with enhanced legend

The link to fixed *.js files will be posted at the end of this article.
Read more of this post

Silverlight sparkline chart

According to Wikipedia

A sparkline is a very small line chart, typically drawn without axes or coordinates.

Though this chart is not included by default to the Silverlight Toolkit library, it is very easy to implement such chart by styling the built-in Line chart. Here is an example which I’ve implemented:

silverlight_sparkline_sample

At first I’ve changed the default control template of the Chart control, I’ve removed all paddings, the chart title, and reduced the minimum height and width of the chart. Also I’ve changed the DataPoint template (made them invisible) and the Polyline template (reduced its thickness). Here is the XAML code:

<UserControl.Resources>
    <Style x:Key="ChartWithoutPaddings" TargetType="chart:Chart">
        <Setter Property="Padding" Value="0" />
        <Setter Property="BorderThickness" Value="0" />
        <Setter Property="ChartAreaStyle">
            <Setter.Value>
                <Style TargetType="Panel">
                    <Setter Property="MinWidth" Value="100" />
                    <Setter Property="MinHeight" Value="20" />
                </Style>
            </Setter.Value>
        </Setter>
        <Setter Property="PlotAreaStyle">
            <Setter.Value>
                <Style TargetType="Grid">
                    <Setter Property="Background" Value="Transparent" />
                </Style>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="chart:Chart">
                    <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
                        <chartingprimitives:EdgePanel x:Name="ChartArea" Style="{TemplateBinding ChartAreaStyle}">
                            <Grid Canvas.ZIndex="-1" Style="{TemplateBinding PlotAreaStyle}" />
                        </chartingprimitives:EdgePanel>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style x:Key="EmptyDataPoint" TargetType="Control">
        <Setter Property="Background" Value="Black" />
        <Setter Property="Template" Value="{x:Null}" />
    </Style>

    <Style x:Key="OnePixelLine" TargetType="Polyline">
        <Setter Property="StrokeThickness" Value="1" />
    </Style>
</UserControl.Resources>

This code is almost all that you need to create a sparkline chart. All that is left is to remove axes. It wasn’t a trivial thing, so I used some kind of a hack: I set their width (for Y axis) and height (for X axis) to zero.

<chart:Chart Style="{StaticResource ChartWithoutPaddings}">
    <chart:LineSeries ItemsSource="{Binding FirstIndexItems}" IndependentValuePath="Number" DependentValuePath="Value" 
                        DataPointStyle="{StaticResource EmptyDataPoint}" 
                        PolylineStyle="{StaticResource OnePixelLine}"  />
    <chart:Chart.Axes>
        <chart:LinearAxis Orientation="X" Height="0" Opacity="0" />
        <chart:LinearAxis Orientation="Y" Width="0" Opacity="0" />
    </chart:Chart.Axes>
</chart:Chart>

Links
Source code: SparklineChartSample.zip

Silverlight and WP7 chart with data point labels

Recently I found the question on stackoverflow in which one user asked how to add labels to data points on WPF/Silverlight/Windows Phone Toolkit charts. Whereas almost every javascript chart can do this, this functionality is absent in Silverlight charts and none of developers cares.

So I wrote a simple class which extended the LinearSeries class and now line charts can be displayed like this:

silverlight_chart_datapointlabels

wp7_chart_datapointlabels

I added labels only for line charts, but if someone needs them for column charts, I can try to implement it as well.
In the current implementation I created the class which inherits the LineSeries class. It has the following properties:
DisplayLabels – You should set it to true explicitly so that labels are displayed. It is false by default.
LabelBindingPath – Optional. You can specify a custom property of your model which will be displayed instead of the value from the Y-axis.
LabelStyle – Optional. You can change foreground, font weight, font size and other properties of labels.

The example of usage:

<chart:Chart Width="600" Height="300">
    <local:ExtendedLineSeries
        ItemsSource="{Binding Items}"
        DependentValuePath="ItemValue"
        IndependentValuePath="Title" 
        DisplayLabels="True"
        LabelBindingPath="ItemValue" />
</chart:Chart>

The complete source code of the class:

public class ExtendedLineSeries : LineSeries
{
    private Canvas _labelsCanvas;
    private Dictionary<DataPoint, TextBlock> _currentLabels = new Dictionary<DataPoint, TextBlock>();

    /// <summary>
    /// Gets or sets a value indicating whether labels should be displayed. 
    /// </summary>
    public bool DisplayLabels { get; set; }

    /// <summary>
    /// Gets or sets the binding path of the label.
    /// </summary>
    public string LabelBindingPath { get; set; }

    /// <summary>
    /// Gets or sets the style of each label.
    /// </summary>
    public Style LabelStyle { get; set; }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        // get a canvas to which the labels will be added
        this._labelsCanvas = (Canvas)this.GetTemplateChild("PlotArea");
        // clear the clip property so that labels are visible even if they exceed the bounds of the chart
        this.Clip = null;
    }

    protected override void UpdateDataPoint(DataPoint dataPoint)
    {
        base.UpdateDataPoint(dataPoint);

        // after the data point is created and added to the chart, we can add a label near it
        if (this.DisplayLabels && dataPoint.Visibility == System.Windows.Visibility.Visible)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() => this.CreateLabel(dataPoint));
        }
    }

    private void CreateLabel(DataPoint dataPoint)
    {
        // this method is also called with the SizeChanged event, so I create the label only one time
        TextBlock label;
        if (this._currentLabels.ContainsKey(dataPoint))
        {
            label = this._currentLabels[dataPoint];
        }
        else
        {
            label = new TextBlock();
            this._labelsCanvas.Children.Add(label);
            this._currentLabels.Add(dataPoint, label);

            label.Style = this.LabelStyle;

            // bind the label text to the specified path, or to dataPoint.DependantValue by default
            Binding binding = this.LabelBindingPath != null
                        ? new Binding(this.LabelBindingPath) { Source = dataPoint.DataContext }
                        : new Binding("DependentValue") { Source = dataPoint };
            BindingOperations.SetBinding(label, TextBlock.TextProperty, binding);
        }

        // calculate a position of the label
        double coordinateY = Canvas.GetTop(dataPoint) - label.ActualHeight; // position the label above the data point
        double coordinateX = Canvas.GetLeft(dataPoint) + dataPoint.ActualHeight / 2 - label.ActualWidth / 2; // center horizontally
        Canvas.SetTop(label, coordinateY);
        Canvas.SetLeft(label, coordinateX);
    }
}

In this code I made an override of the UpdateDataPoint method and each time a DataPoint is updated I update its label.
The code work with Silverlight as well as with Windows Phone 7. For WP7 I used the recompiled library which I published in one of my previous posts.

Source code of the sample application: ChartPointLabelsSample.zip

Windows Phone 7 chart libraries overview. AmCharts

After the previous post I decided to explore the internet and find some other chart libraries for WP7. Unfortunately, there are only two free chart libraries: the previously mentioned Silverlight Toolkit and AmCharts. You can download the last charts here: http://wpf.amcharts.com/download.

This is a very small library and the last time it was updated was more than 1 year ago. It contains only 4 charts: Line, Column, Area, Pie. Here are screenshots of them:

The code for a chart item is quite simple:

<amq:SerialChart Style="{StaticResource chartStyle}" 
		DataSource="{Binding Charts[0].Items}" 
		CategoryValueMemberPath="Month">
	<amq:SerialChart.Graphs>
		<amq:LineGraph ValueMemberPath="Value" Title="Test Chart" />
	</amq:SerialChart.Graphs>
</amq:SerialChart>

For some unknown reason, the pie chart should be created by the different XAML code:

<amq:PieChart DataSource="{Binding Charts[3].Items}"
		TitleMemberPath="Month" 
		ValueMemberPath="Value" />

Advantages of these charts:
1. Free and open source (source code: https://github.com/ailon/amCharts-Quick-Charts);
2. Display the tooltip if you tap a data series;
3. Look better on the phone than the Toolkit charts with the default template.
4. Have small size and must work faster than Toolkit.

Disadvantages:
1. Only 4 kinds of charts;
2. Almost no customization, difficult to apply your own design;
3. Annoying behavior: if you tap the legend or the y-axis they will disappear and you will have to tap once again to display them;

As for me, I would use the Toolkit library and would customize their theme so that it looks more like metro style controls. But this library is good as well if you want just to display a chart without any customization.

The source code of the sample application with AmCharts you can download here: Wp7ChartsSamples.Amcharts.zip

Windows Phone 7 charts. Silverlight Toolkit.

Earlier I thought that WP7 Toolkit had chart controls. But it was surprising for me that charts weren’t ported to the WP7 library and if you want to use them, you have to use the Silverlight 3 toolkit with the S3 controls library as it is described in this post. The thing that I don’t like is that I have to add an extra library and also there is the annoying warning message that the library isn’t compatible with WP7. So I created the WP7 library, downloaded the source code of the toolkit and rewrote some code so that it didn’t use the extra reference.

Now you can use this library, which is more suitable for WP7: System.Windows.Controls.DataVisualization.Toolkit.dll.
For some reason the size of this library is 400kb, slightly larger than the silverlight library, I think it is because I haven’t removed *.xaml files.

As it was already said, the xaml code is the same as in WPF and Silverlight versions:

<charting:Chart>
	<charting:PieSeries Title="Test items" ItemsSource="{Binding Items}" DependentValuePath="ItemValue" IndependentValuePath="Title" />
</charting:Chart>

I’m going to examine some other chart libraries for Windows Phone 7 and I will write about their advantages and disadvantages in future posts.

The source code of the tooolkit charts and the sample application you can download here: WP7ToolkitCharts.zip

Silverlight Chart with reversed Y axis

Recently on StackOverflow.com I’ve found a question about Silverlight charts:
“Is it possible to display a Y LinearAxis in Silverlight in reversed order? Instead of lower numbers at the bottom increasing to the top of the Y axis, I would like to see lower numbers at the top”.

I can’t imagine where such chart can be used, maybe to display a bad revenue report in the best possible way. The chart on the right looks much better than the left one.

two linear charts comparison

Anyway after lot of efforts I’ve managed to create such axis without changing the source code of the Toolkit library, just by using the inheritance so that you can use it so:

<chart:Chart>
	<cr:ReversedAxisColumnSeries ItemsSource="{Binding Items}" DependentValuePath="Value" IndependentValuePath="Title" />
	<cr:ReversedAxisLineSeries ItemsSource="{Binding Items}" DependentValuePath="Value" IndependentValuePath="Title" />
	<chart:Chart.Axes>
		<cr:ReversedLinearAxis Orientation="Y" />
	</chart:Chart.Axes>
</chart:Chart>

Here is links to the solution and inside the post I’ll describe how I’ve implemented these classes.
Source code: ChartReversedAxisSample.zip
Read more of this post

Silverlight chart with a Goal line

Some time ago I needed a chart with a horizontal line describing some desirable value and visually demonstrating a relation between a planned value and actual values. Here is the result:

I tried to handle all possible situations and charts.
A case when the goal value (90) is much higher then the highest value:

A case when the goal value (-20) is lower then 0:

A case when there are both positive and negative values:

The code of the extended chart is rather difficult to explain, so use it as it is.
But I can explain usage of this chart. Here is the code example:

<UserControl.Resources>
    <Style x:Key="ChartGoalLineStyle" TargetType="Polyline" >
        <Setter Property="StrokeThickness" Value="1" />
        <Setter Property="Stroke" Value="#FF27AAE1" />
    </Style>
</UserControl.Resources>
<local:ExtendedChart GoalValue="35" GoalLineOrientation="X" GoalLineStyle="{StaticResource ChartGoalLineStyle}">
    <chart:LineSeries ItemsSource="{Binding Items}" DependentValuePath="Value" IndependentValuePath="Month" />
</local:ExtendedChart>

So there are 3 mandatory properties:
1. GoalValue – the value of the goal in relation to data values. If the data is measured in millions – goal value should be in millions too, if the data is in percents – the goal value should be between 0 and 100. But it is not required, as you have already seen, the goal value can be as well very high or lower then 0.
2. GoalLineOrientation – This value should be “X” for Line,Column,Area charts and “Y” for Bar charts. Must be parallel to an independent non-value axis. I tried to detect preferable orientation automatically, but it is not so easy and can lead to many bugs.
3. GoalLineStyle – Any style which can be applied to the Polyline class. In my example I’ve set only the color and thickness, but it is also possible to make the line dashed, for example.

Optional properties (not required):
1. GoalRectangleStyle – The background between the line and zero-point. you can change its color, borders and so on.
2. IsLegendDisplayed – Some charts look better without the legend, so I added this important option.

Here is source code of the solution: SilverlightChartWithGoalLine.zip