SciChart® the market leader in Fast WPF Charts, WPF 3D Charts, iOS Chart, Android Chart and JavaScript Chart Components
Please note! These examples are new to SciChart Mobile v3 release! SciChart iOS & Android ship with Xamarin.iOS and Xamarin.Android bindings around our native iOS & Android Chart controls, allowing you to create fast & feature rich charts to your Xamarin applications. We include ~90 native iOS examples and 90 Android examples, but now also ~60 Xamarin Chart Examples to help you get started with SciChart. You can download the source for our Xamarin Chart Examples from Github, or browse the source code below.
Demonstrates the speed and power of SciChart in a real-time example. Creates a threadpool timer and pushes 1000 points every 10ms to three series on the chart. The point count quickly rises to the millions of points, and SciChart is still rendering!
SciChart Xamarin iOS and SciChart Xamarin Android supports millions of points out of the box*, and is suitable for use in real-time scientific, medical and trading applications.
*depending on available memory and device.
The C#/Xamarin.iOS/Xamarin.Android source code for the Xamarin Chart Performance Demo example is included below (Scroll down!).
Did you know you can also view the source code from one of the following sources as well?
using System;
using System.Timers;
using Android.OS;
using Android.Widget;
using Java.Lang;
using SciChart.Charting.Model.DataSeries;
using SciChart.Charting.Visuals;
using SciChart.Charting.Visuals.Annotations;
using SciChart.Charting.Visuals.Axes;
using SciChart.Charting.Visuals.RenderableSeries;
using SciChart.Core.Model;
using SciChart.Drawing.Common;
using Xamarin.Examples.Demo.Data;
using Xamarin.Examples.Demo;
using Xamarin.Examples.Demo.Droid.Extensions;
using Xamarin.Examples.Demo.Droid.Fragments.Base;
using Math = Java.Lang.Math;
using Random = System.Random;
using Timer = System.Timers.Timer;
namespace Xamarin.Examples.Demo.Droid.Fragments.Examples
{
[ExampleDefinition("Performance Demo", description: "Draws up to 1 Million points in realtime!", icon: ExampleIcon.RealTime)]
public class PerformanceDemoFragment : ExampleBaseFragment
{
private SciChartSurface Surface => View.FindViewById<SciChartSurface>(Resource.Id.chart);
public override int ExampleLayoutId => Resource.Layout.Example_Single_Realtime_Chart_Fragment;
private static readonly int MaxPointCount = CalculateMaxPointCountToDisplay();
private const int TimerInterval = 10;
private const int BufferSize = 1000;
private readonly MovingAverage _maLow = new MovingAverage(200);
private readonly MovingAverage _maHigh = new MovingAverage(1000);
private int _xValue = 0;
private double _yValue = 10;
private readonly IntegerValues _xValues = new IntegerValues(BufferSize);
private readonly FloatValues _firstYValues = new FloatValues(BufferSize);
private readonly FloatValues _secondYValues = new FloatValues(BufferSize);
private readonly FloatValues _thirdYValues = new FloatValues(BufferSize);
private readonly XyDataSeries<int, float> _mainSeries = new XyDataSeries<int, float>();
private readonly XyDataSeries<int, float> _maLowSeries = new XyDataSeries<int, float>();
private readonly XyDataSeries<int, float> _maHighSeries = new XyDataSeries<int, float>();
private readonly Random _random = new Random(42);
private readonly Handler _uiThreadHandler = new Handler(Looper.MainLooper);
private volatile bool _isRunning = false;
private readonly object _syncRoot = new object();
private Timer _timer;
private TextView _textView;
protected override void InitExample()
{
View.FindViewById<Button>(Resource.Id.start).Click += (sender, args) => Start();
View.FindViewById<Button>(Resource.Id.pause).Click += (sender, args) => Pause();
View.FindViewById<Button>(Resource.Id.reset).Click += (sender, args) => Reset();
var xAxis = new NumericAxis(Activity) {AutoRange = AutoRange.Always};
var yAxis = new NumericAxis(Activity) {AutoRange = AutoRange.Always};
var rs1 = new FastLineRenderableSeries {DataSeries = _mainSeries, StrokeStyle = new SolidPenStyle(0xFF4083B7, 2f.ToDip(Activity))};
var rs2 = new FastLineRenderableSeries {DataSeries = _maLowSeries, StrokeStyle = new SolidPenStyle(0xFFFFA500, 2f.ToDip(Activity))};
var rs3 = new FastLineRenderableSeries {DataSeries = _maHighSeries, StrokeStyle = new SolidPenStyle(0xFFE13219, 2f.ToDip(Activity))};
_textView = new TextView(Activity);
_textView.SetPadding(20, 20, 20, 20);
var annotation = new CustomAnnotation(Activity)
{
CoordinateMode = AnnotationCoordinateMode.Relative,
ZIndex = -1,
X1Value = 0,
Y1Value = 0,
};
annotation.SetContentView(_textView);
using (Surface.SuspendUpdates())
{
Surface.XAxes.Add(xAxis);
Surface.YAxes.Add(yAxis);
Surface.RenderableSeries.Add(rs1);
Surface.RenderableSeries.Add(rs2);
Surface.RenderableSeries.Add(rs3);
Surface.Annotations.Add(annotation);
}
Start();
}
private void Start()
{
if (_isRunning) return;
_isRunning = true;
_timer = new Timer(TimerInterval);
_timer.Elapsed += OnTick;
_timer.AutoReset = true;
_timer.Start();
}
private void Pause()
{
if (!_isRunning) return;
_isRunning = false;
_timer.Stop();
_timer.Elapsed -= OnTick;
_timer = null;
}
private void Reset()
{
if(_isRunning)
Pause();
using (Surface.SuspendUpdates())
{
_mainSeries.Clear();
_maLowSeries.Clear();
_maHighSeries.Clear();
}
_xValue = 0;
_yValue = 10;
_maLow.Clear();
_maHigh.Clear();
}
private void OnTick(object sender, ElapsedEventArgs e)
{
lock (_syncRoot)
{
if (!_isRunning) return;
if (GetPointsCount() < MaxPointCount)
{
DoAppendLoop(_random);
}
else
{
Pause();
}
}
}
private int GetPointsCount()
{
return _mainSeries.Count + _maLowSeries.Count + _maHighSeries.Count;
}
private void DoAppendLoop(Random random)
{
using (Surface.SuspendUpdates())
{
_xValues.Clear();
_firstYValues.Clear();
_secondYValues.Clear();
_thirdYValues.Clear();
for (var i = 0; i < BufferSize; i++)
{
_xValue++;
_yValue += random.NextDouble() - 0.5;
_xValues.Add(_xValue);
_firstYValues.Add((float) _yValue);
_secondYValues.Add((float) _maLow.Push(_yValue).Current);
_thirdYValues.Add((float) _maHigh.Push(_yValue).Current);
}
_mainSeries.Append(_xValues, _firstYValues);
_maLowSeries.Append(_xValues, _secondYValues);
_maHighSeries.Append(_xValues, _thirdYValues);
var count = _mainSeries.Count + _maLowSeries.Count + _maHighSeries.Count;
var text = "Amount of points: " + count;
// need to set text from UI thread to prevent exception
_uiThreadHandler.Post(() =>
{
_textView.SetText(text, TextView.BufferType.Normal);
});
}
}
private static int CalculateMaxPointCountToDisplay()
{
const int oneMlnPointsRequirement = 8 + 16 + 4 + 8;
var memorySize = GetMaxMemorySize() - 40;
var maxPointCount = memorySize/oneMlnPointsRequirement*1000000;
return (int) Math.Round(maxPointCount/3);
}
private static double GetMaxMemorySize()
{
return Runtime.GetRuntime().MaxMemory()/1024.0/1024.0;
}
public override void OnDestroyView()
{
base.OnDestroyView();
Reset();
}
public override void InitExampleForUiTest()
{
base.InitExampleForUiTest();
lock (_syncRoot)
{
Reset();
DoAppendLoop(new Random(42));
}
}
}
}