I am trying to display real time ecg data output from a device to a Winforms chart.
It's working pretty well, but I can't seem to remove the data points from the left hand side of the chart as new points are added, and the major grids shrink and grow.
Here is the code in the timer:
private void butPlayEKG_Click(object sender, EventArgs e) {
chartEKG.Series.Clear();
var series1 = new Series {
Name = "EKG",
Color = Color.LawnGreen,
IsVisibleInLegend = true,
IsXValueIndexed = true,
ChartType = SeriesChartType.Line,
};
this.chartEKG.Series.Add(series1);
playButtonClicked = true;
timer1.Enabled = true;
timer1.Interval = 5;
timer1.Tick += (s, args) => timer1_Tick(series1);
timer1.Start();
}
private void timer1_Tick(Series series1) {
labelClock.Text = DateTime.Now.ToString("HH:mm:ss tt");
string str = String.Empty;
for (int j = 0; j < ekgData.Count; j++) {
str = ekgData[j].EKGWaveform.ToString();
count = str.Split('^');
EKGData = new int[count.Length];
string timeStamp = ekgData[j].VSTimeStamp.ToString();
string format = "yyyyMMddHHmmssfff";
DateTime time = DateTime.ParseExact(timeStamp, format, null);// CultureInfo.InvariantCulture);
adjTime = time;
if (j > 0) {
adjTime = time; time.AddSeconds(1 / 500);
}
for (int i = 0; i < 499; i++) {
EKGData = Array.ConvertAll<string, int>(count, Convert.ToInt32);
series1.Points.AddXY(adjTime.ToString("HH:mm:ss tt"), EKGData[i] * .61);
chartEKG.Update();
}
for (int h = 1; h < j; h++) {
series1.Points.Remove(series1.Points[h]);
chartEKG.Update();
}
}
}
and here is the chart code:
timer1.Interval = 15;
this.chartEKG.ChartAreas["ChartArea1"].CursorX.LineColor = Color.LawnGreen;
this.chartEKG.ChartAreas["ChartArea1"].CursorY.LineColor = Color.LawnGreen;
this.chartEKG.ChartAreas["ChartArea1"].AxisY.MajorGrid.Enabled = true;
this.chartEKG.ChartAreas["ChartArea1"].AxisY.MajorGrid.Interval = 200;
this.chartEKG.ChartAreas["ChartArea1"].AxisX.MajorGrid.Enabled = true;
this.chartEKG.ChartAreas["ChartArea1"].AxisX.MajorGrid.Interval = 200;
this.chartEKG.ChartAreas["ChartArea1"].AxisY.Title = "mV";
this.chartEKG.ChartAreas["ChartArea1"].AxisX.Minimum = 0;
CultureInfo culture = new CultureInfo("en-US");
ekgData = AnesthVSDatas.CreateEKGWaveformObjects(8237);
A video of the playback can be viewed here:
Real time ecg data
Pay attention, time.AddSeconds(1 / 500); has no effect.
I guess you insert every time the same time in the chart.
Maybe your intent was
time = time.AddSeconds(1d / 500);
Note also the d. Because 1/500 is equal to 0.
Working now.
I realized I did not need the timer, and I needed a points.RemoveAt to remove points from the chart as more points are plotted. I also simplified things by Joining all of the messages together into one long string instead of parsing each message individually.
Here is the working code:
private System.Windows.Forms.DataVisualization.Charting.Chart chartEKG;
private System.Windows.Forms.DataVisualization.Charting.Series series1;
private List<AnesthVSData> ekgData;
private static string str;
private string[] count;
chartEKG.Series.Clear();
var series1 = new Series {
Name = "EKG",
Color = Color.LawnGreen,
IsVisibleInLegend = true,
IsXValueIndexed = true,
ChartType = SeriesChartType.Line,
};
this.chartEKG.Series.Add(series1);
playButtonClicked = true;
labelClock.Text = DateTime.Now.ToString("HH:mm:ss tt");
string timeStamp = DateTime.Now.ToString();
for (int j = 0; j < ekgData.Count; j++) {
str = str + "^" + string.Join("^", ekgData[j].EKGWaveform.ToString());
if (j == 0) {
timeStamp = ekgData[j].VSTimeStamp; //get first VSTimeStamp in series
}
}
str = str.Remove(0, 1); //remove leading ^
count = str.Split('^');
string format = "yyyyMMddHHmmssfff";
DateTime time = DateTime.ParseExact(timeStamp, format, CultureInfo.InvariantCulture);
//adjTime = time;
for (int j = 0; j < count.Length; j++) {
time = time.AddSeconds(0.002); //500 data points per HL7 message, each message is 1s long so 1/500 = 0.002
series1.Points.AddXY(time.ToString("HH:mm:ss"), Convert.ToInt32(count[j]) * 0.61); // 0.61 is resolution correction factor
if (chartEKG.Series[0].Points.Count > 1800) {
chartEKG.Series[0].Points.RemoveAt(0);
chartEKG.ChartAreas[0].AxisX.Minimum = 0; }
chartEKG.Update();
}
And here is the output:
ekg waveform demo
Related
How do I remove the time from the X Axis in my chart.
My sql returns date only but my code adds the time again.
I have tried:
Chart1.ChartAreas[0].AxisX.LabelStyle.Format = "##-##-##";
But no luck.
My current code:
Chart1.Visible = ddlChart.SelectedValue != "";
string query = string.Format(stest);
DataTable dt = GetData(query);
string[] x = new string[dt.Rows.Count];
int[] y = new int[dt.Rows.Count];
for (int i = 0; i < dt.Rows.Count; i++)
{
x[i] = dt.Rows[i][0].ToString();
y[i] = Convert.ToInt32(dt.Rows[i][1]);
}
Chart1.Series[0].Points.DataBindXY(x, y);
Chart1.Series[0].ChartType = SeriesChartType.Bar;
Chart1.ChartAreas["ChartArea1"].Area3DStyle.Enable3D = true;
Chart1.Legends[0].Enabled = true;
WORKING CODE - Thanks jstreet
Chart1.Visible = ddlChart.SelectedValue != "";
string query = string.Format(stest);
DataTable dt = GetData(query);
DateTime[] x = new DateTime [dt.Rows.Count];
int[] y = new int[dt.Rows.Count];
for (int i = 0; i < dt.Rows.Count; i++)
{
x[i] = Convert.ToDateTime(dt.Rows[i][0]);
y[i] = Convert.ToInt32(dt.Rows[i][1]);
}
Chart1.Series[0].Points.DataBindXY(x, y);
Chart1.ChartAreas[0].AxisX.LabelStyle.Format = "MM-dd-yyyy";
Chart1.Series[0].ChartType = SeriesChartType.Bar;
Chart1.ChartAreas["ChartArea1"].Area3DStyle.Enable3D = true;
Chart1.Legends[0].Enabled = true;
In a Bar chart (as opposed to a Column chart), the vertical axis is the AxisX, not AxisY. Also, avoid assigning a string to your AxisX. It is not necessary at all and may cause problems.
Use this:
Chart1.ChartAreas[0].AxisX.LabelStyle.Format = "MM-dd-yyyy";
or this:
Chart1.ChartAreas[0].AxisX.LabelStyle.Format = "MM-dd-yy";
EDIT:
Here's some sample code:
protected void Page_Load(object sender, EventArgs e)
{
DateTime[] x = new DateTime[3];
int[] y = new int[3];
for (int i = 0; i < 3; i++)
{
x[i] = DateTime.Now.AddDays(i);
y[i] = 10 * (i + 1);
}
Chart1.Series[0].Points.DataBindXY(x, y);
Chart1.ChartAreas[0].AxisX.LabelStyle.Format = "MM-dd-yy";
}
The following below should work
for (int i=0; i < dt.Rows.Count; i++)
{
DataRow row = dt.Rows[i];
x[i] = DateTime.ParseExact(row[0].ToString(), 'MM-dd-yy', CultureInfo.InvariantCulture);
y[i] = Convert.ToInt32(row[1]);
}
I'm a hobby programmer.
I tried to ask this question earlier on a very unstructured way (Sorry again), now I try to ask on the proper way.
I wrote the following code that seems to work unreliably.
The code was written like this for several reasons. I know it's messy but it should still work. To explain why I wrote it like this would mean that I need to explain several weeks' of work that is quite extensive. Please accept that this is at least the least worse option I could figure out. In the below sample I removed all sections of the code that are not needed to reproduce the error.
What this program does in a nutshell:
The purpose is to check a large number of parameter combinations for a program that receives streaming data. I simulate the original process to test parameter combinations.
First data is read from files that represents recorded streaming data.
Then the data is aggregated.
Then I build a list of parameters to test for.
Finally I run the code for each parameter combination in parallel.
Inside the parallel part I calculate a financial indicator called the bollinger bands. This is a moving average with adding +/- standard deviation. This means the upper line and the lower line should only be equal when variable bBandDelta = 0. However sometimes it happens that CandleList[slot, w][ctr].bollingerUp is equal to CandleList[slot, w][ctr].bollingerDown even when bBandDelta is not 0.
As a result I don't understand how can line 277 kick in. It seems that sometimes the program fails to write to the CandleList[slot, w][ctr]. However this should not be possible because (1) I lock the list and (2) I use ConcurrentBag. Could I have some help please?
Source files are here.
The code is:
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Concurrent;
namespace Justfortest
{
class tick : IComparable<tick> //Data element to represent a tick
{
public string disp_name; //ticker ID
public DateTime? trd_date; //trade date
public TimeSpan? trdtim_1; //trade time
public decimal trdprc_1; //price
public int? trdvol_1; //tick volume
public int CompareTo(tick other)
{
if (this.trdprc_1 == other.trdprc_1)
{
return other.trdprc_1.CompareTo(this.trdprc_1); //Return the later item
}
return this.trdprc_1.CompareTo(other.trdprc_1); //Return the earlier item
}
}
class candle : IComparable<candle> //Data element to represent a candle and all chart data calculated on candle level
{
public int id = 0;
public DateTime? openDate;
public TimeSpan? openTime;
public DateTime? closeDate;
public TimeSpan? closeTime;
public decimal open = 0;
public decimal high = 0;
public decimal low = 0;
public decimal close = 0;
public int? volume = 0;
public decimal totalPrice = 0;
public decimal bollingerUp = 0; //Bollinger upper line
public decimal bollingerDown = 0; //Bollinger below line
public int CompareTo(candle other)
{
if (totalPrice == other.totalPrice)
{
return other.totalPrice.CompareTo(totalPrice); //Return the later item
}
return totalPrice.CompareTo(other.totalPrice); //Return the earlier item
}
}
class param : IComparable<param> //Data element represent a trade event signal
{
public int par1;
public int bollPar;
public int par2;
public int par3;
public int par4;
public int par5;
public int par6;
public decimal par7;
public decimal par8;
public decimal par9;
public decimal par10;
int IComparable<param>.CompareTo(param other)
{
throw new NotImplementedException();
}
}
class programCLass
{
void myProgram()
{
Console.WriteLine("Hello");
Console.WindowWidth = 180;
string[] sources = new string[]
{
#"C:\test\source\sourceW1.csv",
#"C:\test\source\sourceW2.csv",
};
List<candle>[] sourceCandleList = new List<candle>[sources.Count()];
List<param> paramList = new List<param>(10000000);
var csvAnalyzer = new StringBuilder();
{
List<tick>[] updatelist = new List<tick>[sources.Count()];
Console.WriteLine("START LOAD");
for (var i = 0; i < sources.Count(); i++)
{
var file = sources[i];
updatelist[i] = new List<tick>();
// ---------- Read CSV file ----------
var reader = new StreamReader(File.OpenRead(file));
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
var values = line.Split(',');
tick update = new tick();
update.disp_name = values[0].ToString();
update.trd_date = Convert.ToDateTime(values[1]);
update.trdtim_1 = TimeSpan.Parse(values[2]);
update.trdprc_1 = Convert.ToDecimal(values[3]);
update.trdvol_1 = Convert.ToInt32(values[4]);
updatelist[i].Add(update);
}
Console.WriteLine(i);
}
Console.WriteLine("END LOAD"); // All files are in the memory
// Aggreagate
Console.WriteLine("AGGREGATE START");
int tickAggr = 500;
for (var w = 0; w < sources.Count(); w++)
{
sourceCandleList[w] = new List<candle>();
List<tick> FuturesList = new List<tick>();
foreach (var update in updatelist[w])
{
tick t = new tick();
t.disp_name = update.disp_name.ToString();
t.trd_date = update.trd_date;
t.trdtim_1 = update.trdtim_1;
t.trdprc_1 = Convert.ToDecimal(update.trdprc_1);
t.trdvol_1 = update.trdvol_1;
// Add new tick to the list
FuturesList.Add(t);
if (FuturesList.Count == Math.Truncate(FuturesList.Count / (decimal)tickAggr) * tickAggr)
{
candle c = new candle();
c.openDate = FuturesList[FuturesList.Count - tickAggr].trd_date;
c.openTime = FuturesList[FuturesList.Count - tickAggr].trdtim_1;
c.closeDate = FuturesList.Last().trd_date;
c.closeTime = FuturesList.Last().trdtim_1;
c.open = FuturesList[FuturesList.Count - tickAggr].trdprc_1;
c.high = FuturesList.GetRange(FuturesList.Count - tickAggr, tickAggr).Max().trdprc_1;
c.low = FuturesList.GetRange(FuturesList.Count - tickAggr, tickAggr).Min().trdprc_1;
c.close = FuturesList.Last().trdprc_1;
c.volume = FuturesList.GetRange(FuturesList.Count - tickAggr, tickAggr).Sum(tick => tick.trdvol_1);
c.totalPrice = (c.open + c.high + c.low + c.close) / 4;
sourceCandleList[w].Add(c);
if (sourceCandleList[w].Count == 1)
{
c.id = 0;
}
else
{
c.id = sourceCandleList[w][sourceCandleList[w].Count - 2].id + 1;
}
}
}
FuturesList.Clear();
}
Console.WriteLine("AGGREGATE END");
for (var i = 0; i < sources.Count(); i++)
{
updatelist[i].Clear();
}
}
Console.WriteLine("BUILD PARAMLIST");
for (int par1 = 8; par1 <= 20; par1 += 4) // parameter deployed
{
for (int bollPar = 10; bollPar <= 25; bollPar += 5) // parameter deployed
{
for (int par2 = 6; par2 <= 18; par2 += 4) // parameter deployed
{
for (int par3 = 14; par3 <= 20; par3 += 3) // parameter deployed
{
for (int par4 = 10; par4 <= 20; par4 += 5) // parameter deployed
{
for (int par5 = 4; par5 <= 10; par5 += 2) // parameter deployed
{
for (int par6 = 5; par6 <= 30; par6 += 5)
{
for (decimal par7 = 1.0005M; par7 <= 1.002M; par7 += 0.0005M)
{
for (decimal par8 = 1.002M; par8 <= 1.0048M; par8 += 0.0007M)
{
for (decimal par9 = 0.2M; par9 <= 0.5M; par9 += 0.1M)
{
for (decimal par10 = 0.5M; par10 <= 2; par10 += 0.5M)
{
param p = new param();
p.par1 = par1;
p.bollPar = bollPar;
p.par2 = par2;
p.par3 = par3;
p.par4 = par4;
p.par5 = par5;
p.par6 = par6;
p.par7 = par7;
p.par8 = par8;
p.par9 = par9;
p.par10 = par10;
paramList.Add(p);
}
}
}
}
}
}
}
}
}
}
}
Console.WriteLine("END BUILD PARAMLIST, scenarios to test:{0}", paramList.Count);
var sourceCount = sources.Count();
sources = null;
Console.WriteLine("Start building pools");
int maxThreads = 64;
ConcurrentBag<int> pool = new ConcurrentBag<int>();
List<candle>[,] CandleList = new List<candle>[maxThreads, sourceCount];
for (int i = 0; i <= maxThreads - 1; i++)
{
pool.Add(i);
for (int w = 0; w <= sourceCount - 1; w++)
{
CandleList[i, w] = sourceCandleList[w].ConvertAll(p => p);
}
}
Console.WriteLine("End building pools");
int pItemsProcessed = 0;
Parallel.ForEach(paramList,
new ParallelOptions { MaxDegreeOfParallelism = maxThreads },
p =>
{
int slot = 1000;
while (!pool.TryTake(out slot));
var bollPar = p.bollPar;
decimal bollingerMiddle = 0;
double bBandDeltaX = 0;
for (var w = 0; w < sourceCount; w++)
{
lock (CandleList[slot, w])
{
for (var ctr = 0; ctr < CandleList[slot, w].Count; ctr++)
{
CandleList[slot, w][ctr].bollingerUp = 0; //Bollinger upper line
CandleList[slot, w][ctr].bollingerDown = 0; //Bollinger below line
//Bollinger Bands Calculation
if (ctr + 1 >= bollPar)
{
bollingerMiddle = 0;
bBandDeltaX = 0;
for (int i = 0; i <= bollPar - 1; i++)
{
bollingerMiddle = bollingerMiddle + CandleList[slot, w][ctr - i].totalPrice;
}
bollingerMiddle = bollingerMiddle / bollPar; //average
for (int i = 0; i <= bollPar - 1; i++)
{
bBandDeltaX = bBandDeltaX + (double)Math.Pow(System.Convert.ToDouble(CandleList[slot, w][ctr - i].totalPrice) - System.Convert.ToDouble(bollingerMiddle), 2);
}
bBandDeltaX = bBandDeltaX / bollPar;
decimal bBandDelta = (decimal)Math.Sqrt(System.Convert.ToDouble(bBandDeltaX));
CandleList[slot, w][ctr].bollingerUp = bollingerMiddle + 2 * bBandDelta;
CandleList[slot, w][ctr].bollingerDown = bollingerMiddle - 2 * bBandDelta;
if (CandleList[slot, w][ctr].bollingerUp == CandleList[slot, w][ctr].bollingerDown)
{
Console.WriteLine("?! Items processed=" + pItemsProcessed + " bollPar=" + bollPar + " ctr=" + ctr + " bollingerMiddle=" + bollingerMiddle + " bBandDeltaX=" + bBandDeltaX + " bBandDelta=" + bBandDelta + " bollingerUp=" + CandleList[slot, w][ctr].bollingerUp + " bollingerDown=" + CandleList[slot, w][ctr].bollingerDown);
}
}
// REMOVED Further calculations happen here
}
// REMOVED Some evaluations happen here
}
}
// REMOVED Some more evaluations happen here
Interlocked.Increment(ref pItemsProcessed);
pool.Add(slot);
});
}
static void Main(string[] args)
{
var P = new programCLass();
P.myProgram();
}
}
}
Im new at programming, and I am trying to learn Encog 3.3 Library. I worked on making my first network. I was able to write and understand the Code; However, My error rate does not go below 0.79, I used TANH activation function. My network is suppose to return 1 of three values -1,0,1 based on a set of variables I input it. Has anyone Have this same Problem?
this is the Code:
static void Main(string[] args)
{
// creating the neural net : network
var network = new BasicNetwork();
network.AddLayer(new BasicLayer(null, true,21));
network.AddLayer(new BasicLayer( new ActivationTANH(), true,15));
network.AddLayer(new BasicLayer(new ActivationTANH(), true, 15));
network.AddLayer(new BasicLayer(new ActivationTANH(), true,1));
network.Structure.FinalizeStructure();
network.Reset();
// creating the training Data
string Path = "";
var listArray = GetFile(Path);
int amountNumbersY = GetYSize(listArray);
int amountNumbers = GetXSize(listArray[1]);
string[,] matrixString = new string[listArray.Length, amountNumbers]; matrixString = splitter(listArray, amountNumbers);
double[][] allData = new double[amountNumbers][];
for (int i = 0; i < allData.Length; i++)
allData[i] = new double[amountNumbersY];
allData = ConvertToDouble(matrixString, amountNumbers);
// creating the inpuit and output
double[][] XOR_INPUT = new double[amountNumbersY][];
for (int i = 0; i < amountNumbersY; i++)
{
XOR_INPUT[i] = new double[amountNumbers - 1];
}
double[][] XOR_IDEAL = new double[amountNumbersY][];
for (int i = 0; i < amountNumbersY; i++)
{
XOR_IDEAL[i] = new double[1];
}
XOR_INPUT = GetInput(allData, amountNumbers, amountNumbersY, 1);
XOR_IDEAL = GetIdealOutPut(allData, amountNumbers, amountNumbersY, 1);
// normalizing the Arrays
double[][] temp_Input = new double[amountNumbersY-1][];
for (int i = 0; i < amountNumbersY-1; i++) // initializing the x axis
{
temp_Input[i] = new double[amountNumbers - 1];
}
double[][] temp_Ideal = new double[amountNumbersY-1][]; // same as above for output matrix
for (int i = 0; i < amountNumbersY-1; i++)
{
temp_Ideal[i] = new double[1];
}
double[][] closedLoop_temp_Input = new double[amountNumbersY-1][];
for (int i = 0; i < amountNumbersY-1; i++) // initializing the x axis
{
closedLoop_temp_Input[i] = new double[amountNumbers - 1];
}
double[][] closedLoop_temp_Ideal = new double[amountNumbersY-1][];
for (int i = 0; i < amountNumbersY-1; i++)
{
closedLoop_temp_Ideal[i] = new double[1];
}
var hi = 1;
var lo = -1;
var norm = new NormalizeArray { NormalizedHigh = hi, NormalizedLow = lo };
for (int i = 0; i < amountNumbersY-1; i++)
{
temp_Input[i] = norm.Process( XOR_INPUT[i]);
}
closedLoop_temp_Input = EngineArray.ArrayCopy(temp_Input);
var Ideal_Stats = new NormalizedField(NormalizationAction.Normalize,"Temp_Ideal",1,-1,-1,1);
for (int i = 0; i < amountNumbersY - 1; i++)
{
temp_Ideal[i][0] = Ideal_Stats.Normalize(XOR_IDEAL[i][0]);
}
closedLoop_temp_Ideal = EngineArray.ArrayCopy(temp_Ideal);
IMLDataSet trainingSet = new BasicMLDataSet(closedLoop_temp_Input, closedLoop_temp_Ideal);
// training the network
IMLTrain train = new ResilientPropagation( network, trainingSet);
ICalculateScore score = new TrainingSetScore(trainingSet);
IMLTrain annealing = new NeuralSimulatedAnnealing(network,score,10,2,10);
int epoch = 1;
do
{
if (epoch == 50)
{
int i = 0;
do
{
annealing.Iteration();
Console.WriteLine("Annealing: " + i +", Error: " + annealing.Error);
i++;
} while (i < 5);
}
train.Iteration();
Console.WriteLine(#" Epoch: "+epoch+ #", Error: "+train.Error+"...");
epoch ++;
} while ( train.Error<0.01 || epoch < 1000);
// testing the network
}
}
}
The training rate not falling is one of the most common problems in machine learning. Often it is because the data given to the model simply does not support a prediction. You are training a neural network to predict an output given the input. Consider if you were to train on the following inputs and expected outputs. The data might be noisy or it might be contradictory.
A few suggestions. First, dump your training data to a file and have a look at it. Is it what you expect? Are all of the values between -1 and 1. You have quite a bit of code happening before the training. There could be something going wrong there.
You also have a somewhat hybrid training approach going on, with RPROP and annealing. Perhaps just stick to RPROP and see what happens.
I am using file watcher monitoring the file output, and then dynamically display the results using d3 (dynamic data display). Here is more details:
Data are series of tiff file generated one by one quickly (20-25 miliseconds per file generation);
Once there is a file coming in, event is fired, and the file is processed (some stats calculation);
The results will be sent to a d3 plotter, which will dynamically display the results on a charter.
When I close the d3 charter window, the file watcher catcher pretty much all the events, but here is my problem:
However, when I leave the d3 charter window open, even when there is not any stats calculation, the file watcher drop many events (some big gap occurs).
Here is what we have tried:
Increase the watcher buffer, but, it still drop events as long as the d3 charter window is open.
Using C++ dll to calculate stats, but it looks even more slow.
So I am wondering:
Do d3 plotter and file watcher conflict/interfere with each other?
Can I possibly use them together to to real time plot?
Is there anyway to get around my problem?
Any pointers are appreciated.
Here is the code for d3 plotter, including constructor, plotter initiator, and plotter update:
#region Constructor
public SignalStatsDisplay()
{
InitializeComponent();
// timeDomainPlotter.Legend.Remove();
_initialChildrenCount = timeDomainPlotter.Children.Count;
int count = timeDomainPlotter.Children.Count;
//do not remove the initial children
if (count > _initialChildrenCount)
{
for (int i = count - 1; i >= _initialChildrenCount; i--)
{
timeDomainPlotter.Children.RemoveAt(i);
}
}
_nMaxStatsOneChannel = Enum.GetNames(typeof(Window1.ROISignalList)).Length;
_curveBrush = new Brush[_nMaxStatsOneChannel];
_statsEnable = new int[_nMaxStatsOneChannel];
for (int i = 0; i < _nMaxStatsOneChannel; i++)
{
_curveBrush[i] = new SolidColorBrush((Color)ColorConverter.ConvertFromString(_colorList[i]));
_statsEnable[i] = 0;
}
_nActiveStatsOneChannel = 0;
}
#endregion Constructor
public void InitiateSignalAnalysisPlot()
{
_statsName = Enum.GetNames(typeof(Window1.ROISignalList));
int count = 0;
_statsEnableIndex = new int[_nActiveStatsOneChannel];
for (int i = 0; i < _nMaxStatsOneChannel; i++) // assign color
{
if (_statsEnable[i] == 1)
{
_statsEnableIndex[count] = i;
count++;
}
}
if (_nActiveChannel > 0) // timeDomainPlotter init
{
_dataX = new List<double[]>();
_dataY = new List<double[]>();
double[] dataXOneCh = new double[_signalLength];
double[] dataYOneCh = new double[_signalLength];
dataXOneCh[0] = 0;
dataYOneCh[0] = 0;
for (int i = 0; i < _nActiveChannel; i++)
{
for (int j = 0; j < _nActiveStatsOneChannel; j++)
{
_dataX.Add(dataXOneCh); // data x-y mapping init
_dataY.Add(dataYOneCh);
EnumerableDataSource<double> xOneCh = new EnumerableDataSource<double>(dataXOneCh);
EnumerableDataSource<double> yOneCh = new EnumerableDataSource<double>(dataYOneCh);
xOneCh.SetXMapping(xVal => xVal);
yOneCh.SetXMapping(yVal => yVal);
CompositeDataSource dsOneCh = new CompositeDataSource(xOneCh, yOneCh);
LineAndMarker<MarkerPointsGraph> lam = timeDomainPlotter.AddLineGraph(dsOneCh,
new Pen(_curveBrush[_statsEnableIndex[j]], 2),
new CirclePointMarker { Size = 5, Fill = _curveBrush[_statsEnableIndex[j]] },
new PenDescription(_statsName[_statsEnableIndex[j]]));
}
}
Action FitToView = delegate()
{
timeDomainPlotter.FitToView();
};
this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, FitToView);
}
else
{
return;
}
}
public void RedrawSignalAnalysisPlot()
{
int startIndex = _initialChildrenCount;
if ((_nActiveStatsOneChannel > 0) && (_dataX != null) && (_dataY != null))
{
CompositeDataSource[] dsCh = new CompositeDataSource[_nActiveStatsOneChannel];
int m, n;
int index;
for (int i = 0; i < _nActiveChannel; i++)
{
for (int j = 0; j < _nActiveStatsOneChannel; j++)
{
index = i * _nActiveStatsOneChannel + j;
if (_dataX[index].Length == _dataY[index].Length)
{
EnumerableDataSource<double> xOneCh = new EnumerableDataSource<double>(_dataX[index]);
xOneCh.SetXMapping(xVal => xVal);
EnumerableDataSource<double> yOneCh = new EnumerableDataSource<double>(_dataY[index]);
yOneCh.SetYMapping(yVal => yVal);
CompositeDataSource ds = new CompositeDataSource(xOneCh, yOneCh);
Action UpdateData = delegate()
{
m = i * 2;
n = j * 2;
// ((LineGraph)timeDomainPlotter.Children.ElementAt(startIndex + n + m * _nActiveStatsOneChannel)).DataSource = ds;
// ((LineGraph)timeDomainPlotter.Children.ElementAt(startIndex + n + m * _nActiveStatsOneChannel)).LinePen
// = new Pen(new SolidColorBrush(_curveBrush[j]), 1);
((MarkerPointsGraph)timeDomainPlotter.Children.ElementAt(startIndex + n + 1 + m * _nActiveStatsOneChannel)).DataSource = ds;
// ((MarkerPointsGraph)timeDomainPlotter.Children.ElementAt(startIndex + n + 1 + m * _nActiveStatsOneChannel)).Marker
// = new CirclePointMarker { Size = 5, Fill = Brushes.Green };
};
this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, UpdateData);
}
}
}
/* Action PlotFitToView = delegate()
{
timeDomainPlotter.FitToView();
};
this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, PlotFitToView);*/
}
}
Here is how files are monitored:
Where events (file written) are filed
void tiffWatcher_EventChanged(object sender, WatcherExEventArgs e)
{
string fileName = ((FileSystemEventArgs)(e.Arguments)).FullPath;
string fileExt = StringExtension.GetLast(fileName, 4);
if (!IsFileLocked(fileName))
{
Action EventFinished = delegate()
{
CreateListViewItem(fileName, "Finished", DateTime.Now.ToString("HH:mm:ss.fff"));
};
listView1.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, EventFinished);
_tiffName.Add( fileName);
_tiffFilledCount++;
}
}
tiff data processing, and data communication to d3 plotter:
void tiffTimer_Tick(object sender, EventArgs e)
{
//throw new NotImplementedException();
byte[] image = new byte[_signalManager.ImgWidth * _signalManager.ImgHeight];
if (_tiffFilledCount - _tiffProcessedCount >= 1)
{
string fileName = _tiffName[_tiffProcessedCount++];
char filePre = fileName[49];
int indexBeigin = fileName.LastIndexOf("_");
int indexEnd = fileName.LastIndexOf(".");
_signalIndex = Convert.ToInt32(fileName.Substring(indexBeigin + 1, indexEnd - indexBeigin - 1)) - 1; // 0 based//
_deltaT = ExtractTiffDeltaT(fileName, "DeltaT=", 1);
_channelIndex = (int)Enum.Parse(typeof(ChannelList), Convert.ToString(filePre));
TIFFIImageIO.LoadTIFF(fileName, ref image);
_signalManager.Image = image;
for (int i = 0; i < _nActiveStatsOneChannel; i++)
{
_signalManager.GetSignal( _signalDisplay.StatsEnableIndex[i], ref _signal);
UpdateSignal(_channelIndex, i, _tiffProcessedCount-1, _deltaT, _signal);
}
// if( _tiffProcessedCount % 5 == 0)
_signalDisplay.SetData(_XList, _YList, true);
}
}
I use a Timer.Tick to process the file every 50-100 miliseconds, still testing.
The way I handled it was to setup a Timer, cyclically handling calculation, display. So far, it works fine. Of course there will be many events are missing, but we handle large amount of points (thousands of them), so it is OK to hundreds to do the plot. Here is the code:
private Timer _tiffTimer;
void Window1_Loaded(object sender, RoutedEventArgs e)
{
//throw new NotImplementedException();
_tiffTimer = new Timer();
_tiffTimer.Interval = 50; // change interval to change performance
_tiffTimer.Tick += new EventHandler(tiffTimer_Tick);
_tiffTimer.Start();
}
void tiffTimer_Tick(object sender, EventArgs e)
{
//do your stuff here
}
Somewhere in internet I found this code
private void PopulateChart()
{
int elements = 500;
Random r = new Random();
List<double> xValues = new List<double>();
double currentX = 0;
for (int i = 0; i < elements; i++)
{
xValues.Add(currentX);
currentX = currentX + r.Next(1, 2000);
}
List<double> yValues = new List<double>();
for (int i = 0; i < elements; i++)
{
yValues.Add(r.Next(0, 50));
}
// remove all previous series
chart1.Series.Clear();
var series = chart1.Series.Add("MySeries");
series.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Stock;
//series.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Auto;
DateTime baseDate = DateTime.Today;
for (int i = 0; i < xValues.Count; i++)
{
var xDate = baseDate.AddSeconds(xValues[i]);
var yValue = yValues[i];
series.Points.AddXY(xDate, yValue);
}
// show an X label every itme interval (values in minute 60 = 1 hour)
chart1.ChartAreas[series.ChartArea].AxisX.Interval = 100.0;
chart1.ChartAreas[0].AxisX.IntervalType = System.Windows.Forms.DataVisualization.Charting.DateTimeIntervalType.Minutes;
// label format
chart1.ChartAreas[0].AxisX.LabelStyle.Format = "HH:mm:ss";
}
This displays random data in chart with grouping of data with some time interval.
Now I want to put a horizontal scrollbar (x-axis). I tried using code used in this post
Adding a scroll bar to MS Chart control C#
but I couldnot apply it with full functionality.
Can anyone help me in this problem?
You have enable the X axis for zooming.
chart1.ChartAreas["ChartArea1"].CursorX.IsUserEnabled = true;
chart1.ChartAreas["ChartArea1"].CursorX.IsUserSelectionEnabled = true;
chart1.ChartAreas["ChartArea1"].AxisX.ScaleView.Zoomable = true;
chart1.ChartAreas["ChartArea1"].AxisX.ScrollBar.IsPositionedInside = true;