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).
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" |
Run the application again. The RolloverModifier's Tooltips are now synchronizing across the charts.