windowsforms-401813-controls-and-libraries-chart-control-examples-creating-charts-providing-data-how-to-create-a-real-time-chart.md
This topic explains how to create a chart and add new points to its data source in real time.
The chart processes points that are within its viewport. In the following examples, points that are beyond the viewport are removed from the data source - starting from the beginning of the collection.
The following code generates a new data point that is added to the chart each time the Timer.Tick event occurs (every 100 milliseconds). The example uses an ObservableCollection as the data source for a series. ObservableCollection notifies the chart about new items, and the chart is rendered again.
View Example: How to: Create a Real-Time Chart
using DevExpress.Utils;
using DevExpress.XtraCharts;
using System;
using System.Collections.ObjectModel;
using System.Windows.Forms;
namespace RealTimeChartUpdates {
public partial class Form1 : Form {
const int ViewportPointCount = 100;
ObservableCollection<DataPoint> dataPoints = new ObservableCollection<DataPoint>();
public Form1() { InitializeComponent(); }
void Form1_Load(object sender, EventArgs e) {
chartControl1.Titles.Add(new ChartTitle { Text = "Real-Time Charting" });
Series series = new Series();
series.ChangeView(ViewType.Line);
series.DataSource = dataPoints;
series.DataSourceSorted = true;
series.ArgumentDataMember = "Argument";
series.ValueDataMembers.AddRange("Value");
chartControl1.Series.Add(series);
LineSeriesView seriesView = (LineSeriesView)series.View;
seriesView.LastPoint.LabelDisplayMode = SidePointDisplayMode.DiagramEdge;
seriesView.LastPoint.Label.TextPattern = "{V:f2}";
XYDiagram diagram = (XYDiagram)chartControl1.Diagram;
diagram.AxisX.DateTimeScaleOptions.ScaleMode = ScaleMode.Continuous;
diagram.AxisX.Label.ResolveOverlappingOptions.AllowRotate = false;
diagram.AxisX.Label.ResolveOverlappingOptions.AllowStagger = false;
diagram.AxisX.WholeRange.SideMarginsValue = 0;
diagram.DependentAxesYRange = DefaultBoolean.True;
diagram.AxisY.WholeRange.AlwaysShowZeroLevel = false;
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
timer.Interval = 100;
timer.Start();
timer.Tick += Timer_Tick;
}
int counter = 0;
void Timer_Tick(object sender, EventArgs e) {
dataPoints.Add(new DataPoint(DateTime.Now, GenerateValue(counter++)));
if (dataPoints.Count > ViewportPointCount)
dataPoints.RemoveAt(0);
}
double GenerateValue(double x) {
return Math.Sin(x) * 3 + x / 2 + 5;
}
}
public class DataPoint {
public DateTime Argument { get; set; }
public double Value { get; set; }
public DataPoint(DateTime argument, double value) {
Argument = argument;
Value = value;
}
}
}
Imports DevExpress.Utils
Imports DevExpress.XtraCharts
Imports System
Imports System.Collections.ObjectModel
Imports System.Windows.Forms
Namespace RealTimeChartUpdates
Public Partial Class Form1
Inherits Form
Const ViewportPointCount = 100
Private dataPoints As ObservableCollection(Of DataPoint) = New ObservableCollection(Of DataPoint)()
Public Sub New()
Me.InitializeComponent()
End Sub
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
Me.chartControl1.Titles.Add(New ChartTitle With {
.Text = "Real-Time Charting"
})
Dim series As Series = New Series()
series.ChangeView(ViewType.Line)
series.DataSource = dataPoints
series.DataSourceSorted = True
series.ArgumentDataMember = "Argument"
series.ValueDataMembers.AddRange("Value")
Me.chartControl1.Series.Add(series)
Dim seriesView = CType(series.View, LineSeriesView)
seriesView.LastPoint.LabelDisplayMode = SidePointDisplayMode.DiagramEdge
seriesView.LastPoint.Label.TextPattern = "{V:f2}"
Dim diagram = CType(Me.chartControl1.Diagram, XYDiagram)
diagram.AxisX.DateTimeScaleOptions.ScaleMode = ScaleMode.Continuous
diagram.AxisX.Label.ResolveOverlappingOptions.AllowRotate = False
diagram.AxisX.Label.ResolveOverlappingOptions.AllowStagger = False
diagram.AxisX.WholeRange.SideMarginsValue = 0
diagram.DependentAxesYRange = DefaultBoolean.True
diagram.AxisY.WholeRange.AlwaysShowZeroLevel = False
Dim timer As Timer = New Timer()
timer.Interval = 100
timer.Start()
AddHandler timer.Tick, AddressOf Timer_Tick
End Sub
Private counter = 0
Private Sub Timer_Tick(ByVal sender As Object, ByVal e As EventArgs)
dataPoints.Add(New DataPoint(Date.Now, GenerateValue(Math.Min(Threading.Interlocked.Increment(counter), counter - 1))))
If dataPoints.Count > ViewportPointCount Then dataPoints.RemoveAt(0)
End Sub
Private Function GenerateValue(ByVal x As Double) As Double
Return Math.Sin(x) * 3 + x / 2 + 5
End Function
End Class
Public Class DataPoint
Public Property Argument As Date
Public Property Value As Double
Public Sub New(ByVal argument As Date, ByVal value As Double)
Me.Argument = argument
Me.Value = value
End Sub
End Class
End Namespace
The following example uses a separate thread to accumulate data points. A new batch of data points is generated every 15 milliseconds. The chart fetches a new portion of points to visualize at a rate of ten times per second.
View Example: How to: Create a Real-Time Chart and Collect Data in a Separate Thread
using DevExpress.Utils;
using DevExpress.XtraCharts;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
namespace RealTimeChartUpdates {
public partial class Form1 : Form {
const int ViewportPointCount = 5000;
int counter = 0;
Thread dataAcquisitionThread;
bool isEnabled = true;
int lastRawDataIndex = 0;
List<DataPoint> rawData = new List<DataPoint>();
ObservableCollection<DataPoint> viewportData = new ObservableCollection<DataPoint>();
public Form1() { InitializeComponent(); }
void Form1_Load(object sender, EventArgs e) {
dataAcquisitionThread = new Thread(new ThreadStart(AcquireData));
dataAcquisitionThread.Start();
chartControl1.Titles.Add(new ChartTitle { Text = "Real-Time Charting" });
Series series = new Series();
series.ChangeView(ViewType.Line);
series.DataSource = viewportData;
series.DataSourceSorted = true;
series.ArgumentDataMember = "Argument";
series.ValueDataMembers.AddRange("Value");
chartControl1.Series.Add(series);
LineSeriesView seriesView = (LineSeriesView)series.View;
seriesView.LastPoint.LabelDisplayMode = SidePointDisplayMode.SeriesPoint;
seriesView.LastPoint.Label.TextPattern = "{V:f2}";
XYDiagram diagram = (XYDiagram)chartControl1.Diagram;
diagram.AxisX.DateTimeScaleOptions.ScaleMode = ScaleMode.Continuous;
diagram.AxisX.Label.ResolveOverlappingOptions.AllowRotate = false;
diagram.AxisX.Label.ResolveOverlappingOptions.AllowStagger = false;
diagram.AxisX.VisualRange.EndSideMargin = 200;
diagram.DependentAxesYRange = DefaultBoolean.True;
diagram.AxisY.WholeRange.AlwaysShowZeroLevel = false;
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
timer.Interval = 100;
timer.Start();
timer.Tick += Timer_Tick;
}
void AcquireData() {
while (isEnabled) {
Thread.Sleep(15);
lock (rawData) {
for (int i = 0; i < 50; i++)
rawData.Add(new DataPoint(DateTime.Now, GenerateValue(counter++)));
}
}
}
double GenerateValue(double x) { return Math.Sin(x / 1000.0) * 3 * x + x / 2 + 5; }
void Timer_Tick(object sender, EventArgs e) {
lock (rawData) {
for (int i = Math.Max(lastRawDataIndex, rawData.Count - ViewportPointCount); i < rawData.Count; i++)
viewportData.Add(rawData[i]);
lastRawDataIndex = rawData.Count;
while (viewportData.Count > ViewportPointCount)
viewportData.RemoveAt(0);
}
}
protected override void OnClosing(CancelEventArgs e) {
isEnabled = false;
base.OnClosing(e);
}
public class DataPoint {
public DataPoint(DateTime argument, double value) {
Argument = argument;
Value = value;
}
public DateTime Argument { get; set; }
public double Value { get; set; }
}
}
}
Imports DevExpress.Utils
Imports DevExpress.XtraCharts
Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Imports System.Threading
Imports System.Windows.Forms
Namespace RealTimeChartUpdates
Public Partial Class Form1
Inherits Form
Const ViewportPointCount = 5000
Private counter = 0
Private dataAcquisitionThread As Thread
Private isEnabled = True
Private lastRawDataIndex = 0
Private rawData As List(Of DataPoint) = New List(Of DataPoint)()
Private viewportData As ObservableCollection(Of DataPoint) = New ObservableCollection(Of DataPoint)()
Public Sub New()
Me.InitializeComponent()
End Sub
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
dataAcquisitionThread = New Thread(New ThreadStart(AddressOf AcquireData))
dataAcquisitionThread.Start()
Me.chartControl1.Titles.Add(New ChartTitle With {
.Text = "Real-Time Charting"
})
Dim series As Series = New Series()
series.ChangeView(ViewType.Line)
series.DataSource = viewportData
series.DataSourceSorted = True
series.ArgumentDataMember = "Argument"
series.ValueDataMembers.AddRange("Value")
Me.chartControl1.Series.Add(series)
Dim seriesView = CType(series.View, LineSeriesView)
seriesView.LastPoint.LabelDisplayMode = SidePointDisplayMode.SeriesPoint
seriesView.LastPoint.Label.TextPattern = "{V:f2}"
Dim diagram = CType(Me.chartControl1.Diagram, XYDiagram)
diagram.AxisX.DateTimeScaleOptions.ScaleMode = ScaleMode.Continuous
diagram.AxisX.Label.ResolveOverlappingOptions.AllowRotate = False
diagram.AxisX.Label.ResolveOverlappingOptions.AllowStagger = False
diagram.AxisX.VisualRange.EndSideMargin = 200
diagram.DependentAxesYRange = DefaultBoolean.True
diagram.AxisY.WholeRange.AlwaysShowZeroLevel = False
Dim timer As System.Windows.Forms.Timer = New System.Windows.Forms.Timer()
timer.Interval = 100
timer.Start()
AddHandler timer.Tick, AddressOf Timer_Tick
End Sub
Private Sub AcquireData()
While isEnabled
Thread.Sleep(15)
SyncLock rawData
For i = 0 To 50 - 1
rawData.Add(New DataPoint(Date.Now, GenerateValue(Math.Min(Interlocked.Increment(counter), counter - 1))))
Next
End SyncLock
End While
End Sub
Private Function GenerateValue(ByVal x As Double) As Double
Return Math.Sin(x / 1000.0) * 3 * x + x / 2 + 5
End Function
Private Sub Timer_Tick(ByVal sender As Object, ByVal e As EventArgs)
SyncLock rawData
For i = Math.Max(lastRawDataIndex, rawData.Count - ViewportPointCount) To rawData.Count - 1
viewportData.Add(rawData(i))
Next
lastRawDataIndex = rawData.Count
While ViewportData.Count > ViewportPointCount
viewportData.RemoveAt(0)
End While
End SyncLock
End Sub
Protected Overrides Sub OnClosing(ByVal e As CancelEventArgs)
isEnabled = False
MyBase.OnClosing(e)
End Sub
Public Class DataPoint
Public Sub New(ByVal argument As Date, ByVal value As Double)
Me.Argument = argument
Me.Value = value
End Sub
Public Property Argument As Date
Public Property Value As Double
End Class
End Class
End Namespace
See Also