ファイル出力を監視するファイル ウォッチャーを使用し、d3 (動的データ表示) を使用して結果を動的に表示します。詳細は次のとおりです。
- データは、1 つずつすばやく生成される一連の tiff ファイルです (ファイル生成あたり 20 ~ 25 ミリ秒)。
- ファイルが入ってくると、イベントが発生し、ファイルが処理されます (いくつかの統計計算)。
- 結果は d3 プロッターに送信され、チャーターに動的に結果が表示されます。
d3チャーターウィンドウを閉じると、ファイルウォッチャーはほとんどすべてのイベントをキャッチしますが、ここに私の問題があります:
- ただし、d3 チャーター ウィンドウを開いたままにしておくと、統計計算がない場合でも、File Watcher は多くのイベントをドロップします (いくつかの大きなギャップが発生します)。
これが私たちが試したことです:
- ウォッチャー バッファーを増やしますが、d3 チャーター ウィンドウが開いている限り、イベントはドロップされます。
- C++ dll を使用して統計を計算しますが、さらに遅く見えます。
だから私は疑問に思っています:
- d3 プロッターとファイル ウォッチャーは競合/干渉しますか?
- それらを一緒に使用してリアルタイムでプロットすることはできますか?
- とにかく私の問題を回避する方法はありますか?
任意のポインタをいただければ幸いです。
コンストラクター、プロッター イニシエーター、プロッター更新を含む d3 プロッターのコードを次に示します。
#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);*/
}
}
ファイルの監視方法は次のとおりです。 イベント (ファイルの書き込み) がファイルされる場所
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 データ処理、および d3 プロッターへのデータ通信:
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);
}
}
私は Timer.Tick を使用して、50 ~ 100 ミリ秒ごとにファイルを処理しますが、まだテスト中です。