SciChart WPF 2D Charts > Tutorials > Code-Behind > Tutorial 07 - Adding Annotations
Tutorial 07 - Adding Annotations

In the first tutorial: Creating a SciChartSurface, we touched on a powerful API - the Annotations API.

Source code for this tutorial can be found at our SciChart.WPF.Examples Github Repository under Tutorials section.

This API allows you to add UIElements to the chart: Lines, Text, Boxes, Arrows, custom Markers. The markers update as you zoom and pan the chart.

We're going to build on our previous Tutorial: Adding Realtime Updates to add annotations to a chart in a realtime context.

Revision from Previous Tutorials

First up, if your XAML and Code behind don't look like this then do some copy-pasting and get up to date. This is what your code should look like at the start of the tutorial.

XAML - BEFORE adding annotations
Copy Code
<Window x:Class="SciChart.Tutorial.MainWindow"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:s="http://schemas.abtsoftware.co.uk/scichart"
         mc:Ignorable="d"
         Title="MainWindow" Height="550" Width="800">
    <Grid Background="#222">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
       
        <s:SciChartSurface x:Name="sciChartSurface">
            <s:SciChartSurface.RenderableSeries>
                <s:FastLineRenderableSeries x:Name="LineSeries" Stroke="#FF4083B7"/>
                <s:XyScatterRenderableSeries x:Name="ScatterSeries" >
                    <s:XyScatterRenderableSeries.PointMarker>
                        <s:EllipsePointMarker Width="7" Height="7" Fill="#FFF" Stroke="SteelBlue"/>
                    </s:XyScatterRenderableSeries.PointMarker>
                </s:XyScatterRenderableSeries>
            </s:SciChartSurface.RenderableSeries>
            <s:SciChartSurface.XAxis>
                <s:NumericAxis AxisTitle="Number of Samples (per Series)"/>
            </s:SciChartSurface.XAxis>
            <s:SciChartSurface.YAxis>
                <s:NumericAxis AxisTitle="Value" GrowBy="0.1, 0.1" VisibleRange="-1.1, 1.1"/>
            </s:SciChartSurface.YAxis>
            <s:SciChartSurface.ChartModifier>
                <s:ModifierGroup>
                    <s:RubberBandXyZoomModifier ExecuteOn="MouseLeftButton"
                                                 RubberBandFill="#33FFFFFF" RubberBandStroke="#AAFFFFFF"
                                                 RubberBandStrokeDashArray="2 2"/>
                    <s:ZoomPanModifier ExecuteOn="MouseRightButton" ClipModeX="None" />
                    <s:YAxisDragModifier DragMode="Scale"/>
                    <s:XAxisDragModifier DragMode="Pan"/>
                    <s:MouseWheelZoomModifier/>
                    <s:ZoomExtentsModifier ExecuteOn="MouseDoubleClick" />
                    <!-- NEW CODE HERE -->
                   
                    <!-- Add a Legend to the chart -->
                    <!-- where xmlns:s="http://schemas.abtsoftware.co.uk/scichart" -->
                    <s:LegendModifier ShowLegend="True" Orientation="Horizontal"
                                       VerticalAlignment="Bottom"                                     
                                       HorizontalAlignment="Center"
                                       LegendPlacement="Inside" />
                    <!-- Add a RolloverModifier to the chart (shows vertical line tooltips -->
                    <s:RolloverModifier ExecuteOn="MouseMove" ShowTooltipOn="MouseHover"/>
                    <!-- END NEW CODE -->
                </s:ModifierGroup>
            </s:SciChartSurface.ChartModifier>
            <s:SciChartSurface.Annotations>
                <s:TextAnnotation Text="Hello world!" X1="5.0" Y1="5"/>
            </s:SciChartSurface.Annotations>
        </s:SciChartSurface>
       
        <s:SciChartScrollbar Grid.Row="1" Axis="{Binding ElementName=sciChartSurface, Path=XAxis}"/>
    </Grid>
</Window>
Code Behind - BEFORE adding Annotations
Copy Code
using System;
using System.Windows;
using System.Windows.Threading;
using SciChart.Charting.Model.DataSeries;
using SciChart.Data.Model;
namespace SciChart.Tutorial
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.Loaded += OnLoaded;
        }
        private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
        {
            double windowSize = 1000.0;
            sciChartSurface.ViewportManager = new ScrollingViewportManager(windowSize);
            // Create DataSeries with FifoCapacity
            var scatterData = new XyDataSeries<double, double>() {SeriesName = "Cos(x)",};
            var lineData = new XyDataSeries<double, double>() {SeriesName = "Sin(x)",};
            // Assign DataSeries to RenderableSeries
            LineSeries.DataSeries = lineData;
            ScatterSeries.DataSeries = scatterData;
            int i = 0;
            // Start a timer to update our data
            var timer = new DispatcherTimer(DispatcherPriority.Render);
            timer.Interval = TimeSpan.FromMilliseconds(10);
            timer.Tick += (s, e) =>
            {
                // This time we will append, not update.
                using (lineData.SuspendUpdates())
                using (scatterData.SuspendUpdates())
                {
                    // Append a new data point;
                    lineData.Append(i, Math.Sin(i * 0.1));
                    scatterData.Append(i, Math.Cos(i * 0.1));
                    // Set VisibleRange to last 1,000 points
                    i++;
                }
            };
            timer.Start();
        }
    }
}

Next: Adding the Annotations to the Chart

We are going to add a custom annotation to mark areas of interest on the chart. In this case we're going to borrow the NewsBulletAnnotation from the Trade Markers example. The code for the NewsBulletAnnotation is found below:

Add a new Item to the Project. Choose type UserControl and name it InfoAnnotation.xaml

Now paste the following code into the XAML and Code Behind:

InfoAnnotation.Xaml
Copy Code

<s:CustomAnnotation x:Class="SciChart.Tutorial.InfoAnnotation"
                    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:s="http://schemas.abtsoftware.co.uk/scichart"
                    VerticalAnchorPoint="Bottom"
                    HorizontalAnchorPoint="Center">

    <s:CustomAnnotation.Resources>
        <LinearGradientBrush x:Key="infoAnnotationBackground" StartPoint="0,0" EndPoint="0,1">
            <GradientStop Offset="0.5" Color="#FFF" />
            <GradientStop Offset="1" Color="#77C0D4EE" />
        </LinearGradientBrush>
    </s:CustomAnnotation.Resources>

    <Grid>

        <!-- Low-cost drop shadow -->
        <Border CornerRadius="2" BorderThickness="1" BorderBrush="#333" Background="#333" Opacity="0.8" Margin="2,2,0,0"/>

        <!-- News bullet body -->
        <Border CornerRadius="2" BorderThickness="1" BorderBrush="#555" Background="{StaticResource infoAnnotationBackground}">
            <TextBlock Text="N" Padding="3" FontWeight="Bold" FontSize="10"/>
        </Border>

        <!-- Creating the tooltip. In the TradeOverlayExampleViewModel we set a News
       object as datacontext of this annotation -->
        <ToolTipService.ToolTip>
            <ToolTip Foreground="#222">
                <Grid Margin="6" MaxHeight="100" MaxWidth="150">
                    <TextBlock Text="Show more info here!" Foreground="#3333FF"/>
                </Grid>
            </ToolTip>
        </ToolTipService.ToolTip>
    </Grid>

</s:CustomAnnotation>

InfoAnnotation.xaml.cs
Copy Code
using SciChart.Charting.Visuals.Annotations;
namespace SciChart.Tutorial
{
    public partial class InfoAnnotation : CustomAnnotation
    {
        public InfoAnnotation()
        {
            InitializeComponent();
        }
    }
}

Adding Annotations to the Chart

To add annotations to the chart, you simply need to add a new AnnotationBase derived class to SciChartSurface.Annotations collection and set X1, Y1 (optionally X2, Y2 for lines, boxes).

We're going to do this inside the DispatcherTimer.Tick event following on from our previous tutorial on Realtime Scrolling charts.

Modify the Timer.Tick event as follows:

Adding Annotations in Realtime
Copy Code
timer.Tick += (s, e) =>
{
    // This time we will append, not update.
    using (lineData.SuspendUpdates())
    using (scatterData.SuspendUpdates())
    {
        // Append a new data point;
        lineData.Append(i, Math.Sin(i * 0.1));
        scatterData.Append(i, Math.Cos(i * 0.1));
        // Every 100th datapoint, add an annotation
        if (i%100 == 0)
        {
            sciChartSurface.Annotations.Add(new InfoAnnotation() { X1 = i, Y1 = 0.0});
            // Optional: Don't forget to remove annotations which are out of range!
            sciChartSurface.Annotations.RemoveWhere(x => x.X1.ToDouble() < i-1000);
        }
        i++;
    }
   
};

That's it! If you run the application now, every 100 points you will see an Annotation added to the chart. We also remove annotations that are out of range to stop never-ending memory growth.

Further reading

See Also