iOS Charting Documentation - SciChart
Tutorial 07 - Adding Annotations

In the prior tutorials we have familiarized with a great and powerful SciChart functionality. In this one we are going to play around with one more cool thing SciChart supports - Annotations!

We are going to build on our previous Tutorial 06 - Adding RealTime Updates to add annotations to a chart in a realtime context.
But, let's take a look at how can we add simple annotation like Line, Box or Text.

Adding simple annotations

Let's add simple Text annotation with "Hello SciChart world" text. To do that, we only need to create instance of TextAnnotation and attach to the scichart surface instance:

adding Text annotation
Copy Code
        let textAnnotation = SCITextAnnotation()
        textAnnotation.xAxisId = "xAxis"
        textAnnotation.yAxisId = "yAxis"
        textAnnotation.coordinateMode = .relative
        textAnnotation.x1 = SCIGeneric(0.7)
        textAnnotation.y1 = SCIGeneric(0.5)
        textAnnotation.text = "Hello SciChart world" = 18 = UIColor.white = UIColor.clear
        chartSurface?.annotations = textAnnotation

Adding custom annotation

Before we will start to work on creating custom annotations, let's check we are on the same page. The source code of our ViewController class should look like as follow:

ViewController class
Copy Code
import UIKit
import SciChart
class ViewController: UIViewController {
    var sciChartSurface: SCIChartSurface?
    var lineDataSeries: SCIXyDataSeries!
    var scatterDataSeries: SCIXyDataSeries!
    var lineRenderableSeries: SCIFastLineRenderableSeries!
    var scatterRenderableSeries: SCIXyScatterRenderableSeries!
    var timer: Timer?
    var phase = 0.0
    var i = 0
    let totalCapacity = 500.0
    override func viewDidLoad() {
        // Do any additional setup after loading the view, typically from a nib.
        sciChartSurface = SCIChartSurface(frame: self.view.bounds)
        sciChartSurface?.autoresizingMask = [.flexibleHeight, .flexibleWidth]
        sciChartSurface?.translatesAutoresizingMaskIntoConstraints = true
        let xAxis = SCINumericAxis()
        xAxis.growBy = SCIDoubleRange(min: SCIGeneric(0.1), max: SCIGeneric(0.1))
        // adding some paddding for Y axis
        let yAxis = SCINumericAxis()
        yAxis.growBy = SCIDoubleRange(min: SCIGeneric(0.1), max: SCIGeneric(0.1))
    override func viewWillAppear(_ animated: Bool) {
        if nil == timer{
            timer = Timer.scheduledTimer(withTimeInterval: 0.001, repeats: true, block: updatingDataPoints)
    override func viewWillDisappear(_ animated: Bool) {
        // invalidating timer
        // Timer is a class which is not under ARC umrella, so we need to control it by ourselves
        if nil != timer{
            timer = nil
    func updatingDataPoints(timer:Timer){
        i += 1
        // appending new data points into the line and scatter data series
        lineDataSeries.appendX(SCIGeneric(i), y: SCIGeneric(sin(Double(i)*0.1 + phase)))
        scatterDataSeries.appendX(SCIGeneric(i), y: SCIGeneric(cos(Double(i)*0.1 + phase)))
        phase += 0.01        
    func createDataSeries(){
        // Init line data series
        lineDataSeries = SCIXyDataSeries(xType: .int16, yType: .double)
        lineDataSeries.fifoCapacity = Int32(totalCapacity)
        lineDataSeries.seriesName = "line series"
        // Init scatter data series
        scatterDataSeries = SCIXyDataSeries(xType: .int16, yType: .double)
        scatterDataSeries.fifoCapacity = Int32(totalCapacity)
        scatterDataSeries.seriesName = "scatter series"
        for i in 0...Int32(totalCapacity){
            lineDataSeries.appendX(SCIGeneric(i), y: SCIGeneric(sin(Double(i)*0.1)))
            scatterDataSeries.appendX(SCIGeneric(i), y: SCIGeneric(cos(Double(i)*0.1)))
        i = Int(lineDataSeries.count())
    func createRenderableSeries(){
        lineRenderableSeries = SCIFastLineRenderableSeries()
        lineRenderableSeries.dataSeries = lineDataSeries
        scatterRenderableSeries = SCIXyScatterRenderableSeries()
        scatterRenderableSeries.dataSeries = scatterDataSeries
    func addModifiers(){
        let xAxisDragmodifier = SCIXAxisDragModifier()
        xAxisDragmodifier.dragMode = .pan
        xAxisDragmodifier.clipModeX = .none
        let yAxisDragmodifier = SCIYAxisDragModifier()
        yAxisDragmodifier.dragMode = .pan
        let extendZoomModifier = SCIZoomExtentsModifier()
        let pinchZoomModifier = SCIPinchZoomModifier()
        let rolloverModifier = SCIRolloverModifier()
        let legend = SCILegendModifier()
        let groupModifier = SCIChartModifierCollection(childModifiers: [xAxisDragmodifier, yAxisDragmodifier, pinchZoomModifier, extendZoomModifier, legend, rolloverModifier])
        sciChartSurface?.chartModifiers = groupModifier

And the application should work just like this:

Next: Adding the Custom Annotations to the Chart

The SciChart framework you are currantly using already has a CustomAnnotation class. Pretty simple at a glance, it allows you to use your custom annotation - whatever class inherited from UIVIew class. For example, let's say, we would like to have a custom "text" annotation with "Y" text and place it on every X=100 position. In this case what we need is to declare the UILabel instance and set it to the SCICustomAnnotation's contentView property, just like in the following code:

ViewController class
Copy Code
import UIKit
import SciChart
class ViewController: UIViewController {
    // annotation collection property, used to store all annotations
    let annotationGroup = SCIAnnotationCollection()
    override func viewDidLoad() {
        // set chartSurface's annotation property to annotationGroup
        sciChartSurface?.annotations = annotationGroup
    func updatingDataPoints(timer:Timer){
        if (i%100 == 0){
            let customAnnotation = SCICustomAnnotation()
            let customAnnotationContentView = UILabel(frame: CGRect.init(x: 0, y: 0, width: 10, height: 10))
            customAnnotationContentView.text = "Y"
            customAnnotationContentView.backgroundColor = UIColor.lightGray
            customAnnotation.contentView = customAnnotationContentView
            customAnnotation.x1 = SCIGeneric(i)
            customAnnotation.y1 = SCIGeneric(0.5)
            customAnnotation.coordinateMode = .relativeY
            // adding new custom annotation into the annotationGroup property
            // removing annotations that are out of visible range
            let customAn = annotationGroup.item(at: 0) as! SCICustomAnnotation
            if(SCIGenericDouble(customAn.x1) < Double(i) - totalCapacity){
                // since the contentView is UIView element - we have to call removeFromSuperView method to remove it from screen

As a result we should now see an application with following behavior:

Further reading

Tutorials Repository

As it was mentioned previously - we've created Git repository with all Tutorials. So you can clone/download the appropriate project you need!