Android & Xamarin.Android Charting Documentation - SciChart Android Charts SDK v2.x
Xamarin Tutorial 09 - Linking Multiple Charts

In our series of tutorials, up until now we have added a chart with two YAxis, one XAxis, two series, added tooltips, legends and zooming, panning behavior, and added some annotations. The previous tutorial can be found at this link: Xamarin Tutorial 08 - Adding Multiple Axis.

Next, we are going to show you how to create multiple charts and link them together.

Revision

If you haven't already, you will need to review the following tutorials, as we are working straight from these:

Before next step we'll need to refactor our code and extract some parts ( like creation XAxes, YAxes and Modifiers ) which we can reuse into seperate method. Let's call this method InitChart. It accepts SciChartSurface instance and add one XAxis and two YAxes. Also it add some modifiers. Here its code:

Initialize Chart with XAxes, YAxes and Modifiers
Copy Code
private void InitChart(SciChartSurface chart)
{
    // Create a numeric X axis
    var xAxis = new NumericAxis(this) {AxisTitle = "Number of Samples (per Series)"};
    // Create a numeric Y axis
    var yAxis = new NumericAxis(this)
    {
        AxisTitle = "Value",
        VisibleRange = new DoubleRange(-1, 1)
    };
    // Create a secondary numeric Y Axis
    var secondaryYAxis = new NumericAxis(this)
    {
        AxisTitle = "Secondary",
        AxisId = "SecondaryAxis",
        AxisAlignment = AxisAlignment.Left,
        VisibleRange = new DoubleRange(-2, 2)
    };
    // Create interactivity modifiers
    var pinchZoomModifier = new PinchZoomModifier();
    pinchZoomModifier.SetReceiveHandledEvents(true);
    var zoomPanModifier = new ZoomPanModifier();
    zoomPanModifier.SetReceiveHandledEvents(true);
    var zoomExtentsModifier = new ZoomExtentsModifier();
    zoomExtentsModifier.SetReceiveHandledEvents(true);
    // Create RolloverModifier to show tooltips
    var rolloverModifier = new RolloverModifier();
    rolloverModifier.SetReceiveHandledEvents(true);
    var yAxisDragModifier = new YAxisDragModifier();
    yAxisDragModifier.SetReceiveHandledEvents(true);
    // Create and configure legend
    var legendModifier = new LegendModifier(this);
    legendModifier.SetLegendPosition(GravityFlags.Bottom | GravityFlags.CenterHorizontal, 10);
    legendModifier.SetOrientation(Orientation.Horizontal);
    var modifiers = new ModifierGroup(pinchZoomModifier, zoomPanModifier, zoomExtentsModifier, rolloverModifier,
        legendModifier, yAxisDragModifier);
    // Add xAxis to the XAxes collection of the chart
    chart.XAxes.Add(xAxis);
    // Add yAxis to the YAxes collection of the chart
    chart.YAxes.Add(yAxis);
    // Add secondaryYAxis to the YAxes collection of the chart
    chart.YAxes.Add(secondaryYAxis);
    // Add the interactions to the ChartModifiers collection of the chart
    chart.ChartModifiers.Add(modifiers);
}

Then our OnCreate method will have next code:

Initialize Chart
Copy Code
// Get our chart from the layout resource,
var chart = FindViewById<SciChartSurface>(Resource.Id.Chart);

// Init chart with axes and modifiers 
InitChart(chart);

const int fifoCapacity = 500;
// Create XyDataSeries to host data for our chart
var lineData = new XyDataSeries<double, double>() {SeriesName = "Sin(x)", FifoCapacity = new Integer(fifoCapacity)};
var scatterData = new XyDataSeries<double, double>() {SeriesName = "Cos(x)",FifoCapacity = new Integer(fifoCapacity)};

var x = lineData.Count;
var timer = new Timer(30) {AutoReset = true};
// Append on each tick of timer
timer.Elapsed += (s, e) =>
{
    using (chart.SuspendUpdates())
    {
        lineData.Append(x, Math.Sin(x*0.1));
        scatterData.Append(x, Math.Cos(x*0.1));

        // add label every 100 data points
        if (x%100 == 0)
        {
            // create text annotation with label
            var label = new TextAnnotation(this)
            {
                Text = "N",
                X1Value = x,
                Y1Value = 0,
                HorizontalAnchorPoint = HorizontalAnchorPoint.Center,
                VerticalAnchorPoint = VerticalAnchorPoint.Center,
                FontStyle = new FontStyle(20, Color.White),
                Background = new ColorDrawable(Color.DarkGreen),
                ZIndex = 1,
                YAxisId = x%200 == 0 ? AxisBase.DefaultAxisId : "SecondaryAxis"
            };

            // add label into annotation collection
            chart.Annotations.Add(label); 

            // if we add annotation and x > fifoCapacity
            // then we need to remove annotation which goes out of the screen
            if (x > fifoCapacity)
                chart.Annotations.Remove(0);

        }
      
        // zoom series to fit viewport size into XAxis direction
        chart.ZoomExtentsX();
        x++;
    }
};
timer.Start();

// Create line series with data appended into lineData
var lineSeries = new FastLineRenderableSeries()
{
    DataSeries = lineData,
    StrokeStyle = new SolidPenStyle(Color.LightBlue, 2)
};

// Create scatter series with data appended into scatterData
var scatterSeries = new XyScatterRenderableSeries()
{
    DataSeries = scatterData,
    PointMarker = new EllipsePointMarker()
    {
        Width = 10,
        Height = 10,
        StrokeStyle = new SolidPenStyle(Color.Green, 2),
        FillStyle = new SolidBrushStyle(Color.LightBlue)
    },
    YAxisId = "SecondaryAxis"
};
 
// Add the renderable series to the RenderableSeries collection of the chart
chart.RenderableSeries.Add(lineSeries);
chart.RenderableSeries.Add(scatterSeries);

 

Adding a Second Chart

Now we are going to do almost the same to create and configure the second chart. For example purposes, lets put aside the annotations part and modifiers part for now. Everything else will be the same. The code below adds one more SciChartSurface to the application.

 

First, we need to declare second chart in our layout file:

Declaring second SciChartSurface Instance
Copy Code
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.scichart.charting.visuals.SciChartSurface
       android:id="@+id/Chart"
       android:layout_width="fill_parent"
       android:layout_height="0px"
       android:layout_weight="1"/>
    <com.scichart.charting.visuals.SciChartSurface
       android:id="@+id/SecondChart"
       android:layout_width="fill_parent"
       android:layout_height="0px"
       android:layout_weight="1"/>
 
</LinearLayout>

 Then need to get and initialize it in code:

Example Title
Copy Code
// Get the second chart from the layout resource.
var secondChart = FindViewById<SciChartSurface>(Resource.Id.SecondChart);

// Init secondChart with axes and modifiers
InitChart(secondChart);

With this addition, your application should now show a view with two charts on it:

Adding a Series to the Second Chart

Now we are ready to add a RenderableSeries to the second chart. For the versatility's sake, lets try out another RenderableSeries type, say, FastMountainRenderableSeries. We are going to attach an existing DataSeries to it so it appears scrolling just like the series on the first chart. Also, the new RenderableSeries is going to be attached to the axis width default axis id (in our case it is the right axis).

Remember, since there are two Y axes, they both must have unique IDs assigned to them. Those IDs can be used to register RenderableSeries and Annotations on a corresponding axis.

 So lets add these missing lines to the code:

Add RenderableSeries to the second Chart
Copy Code
// create mountain series with same data which we appended into scatter series
var mountainSeries = new FastMountainRenderableSeries()
{
    DataSeries = scatterData,
    StrokeStyle = new SolidPenStyle(Color.LightSteelBlue),
    AreaStyle = new SolidBrushStyle(Color.SteelBlue),
}

// Add the renderable series to the RenderableSeries collection of the second chart
secondChart.RenderableSeries.Add(mountainSeries);

Synchronizing VisibleRanges on Axes

To make both charts showing same VisibleRanges on axes, you should just share the same IRange instance across the axes. In our case, we're going to assign VisibleRange of one xAxis to VisibleRange of the another xAxis:

Share VisibleRange from top Chart with bottom Chart
Copy Code
// Share chart's XAxis VisibleRange with secondChart's XAxis VisibleRange           
secondChart.XAxes[0].VisibleRange = chart.XAxes[0].VisibleRange;

Now run the application again:

Linking Cursor and Other Modifiers

The next thing we are going to do is to link chart modifiers. Because we use have added modifiers inside InitChart method both charts have the same set of modifiers. Now to sync them we just need to add them to the same MotionEventGroup and to ensure that events from one chart will be received by the other charts in group:

Provide MotionEventGroup for Modifiers
Copy Code
var modifiers = new ModifierGroup(pinchZoomModifier, zoomPanModifier, zoomExtentsModifier, rolloverModifier, legendModifier, yAxisDragModifier);

// Receive events from other charts even if they were handled
modifiers.SetReceiveHandledEvents(true);

// Assing same MotionEventGroup for all charts
modifiers.MotionEventGroup = "SharedEvents"
Hint! You can use a MouseEventGroup on more than two charts. You can also bind this value to a ViewModel property to make it dynamic.Type your Tip Box content here.

Run the application again. The RolloverModifier's Tooltips are now synchronizing across the charts.