04-20-2018 06:16 AM
Hi,
We have an asynchronous method that produces Frequency data and plotting then in a GraphControl.
We want to split window and show another Intensity graph with same data changing over time.
Our intensity graphs XAxis is Frequency and YAxis is Time (TimeSpan or some round trip count) and color scale contains amplitude values.
I found this question M18436. its similar to my request .
How do we configure this example code to scroll (flow) YAxis over time?
Best Regards,
Muhammed,
Solved! Go to Solution.
04-23-2018 01:01 PM
M18436 is the most appropriate example. Unfortunately, the graphs and data collections do not currently have any built-in configuration support for vertical scroll/history. However, you can use a custom data collection to achieve that effect:
[DataTypeDescriptor( typeof( GraphDataCollectionDescriptor<> ) )] public sealed class VerticalIntensityChartCollection<TIndex, TSample> : IGraphDataCollection where TIndex : IComparable<TIndex> { private readonly ChartCollection<TIndex, TSample[]> _chartCollection; public VerticalIntensityChartCollection( int capacity ) { _chartCollection = new ChartCollection<TIndex, TSample[]>( capacity ); } public int Count { get { return DataCollection.Count; } } public Sample<TIndex, TSample[]> this[int index] { get { return _chartCollection[index]; } } public void Append( TIndex index, TSample[] value ) { _chartCollection.Append( index, value ); } #region IGraphDataCollection Members private static readonly ReadOnlyCollection<Type> _dataTypes = new ReadOnlyCollection<Type>( new[] { typeof( int ), typeof( TIndex ), typeof( TSample ) } ); private IGraphDataCollection DataCollection { get { return _chartCollection; } } public bool? MarkIndexData { get { return DataCollection.MarkIndexData; } set { DataCollection.MarkIndexData = value; } } event EventHandler<GraphCollectionChangedEventArgs> IGraphDataCollection.DataChanged { add { DataCollection.DataChanged += value; } remove { DataCollection.DataChanged -= value; } } ReadOnlyCollection<Type> IGraphDataCollection.GetDataTypes( ) { return _dataTypes; } BufferCollection IGraphDataCollection.GetDataBuffers( Trait decomposeOption ) { // Expand and re-order the buffers from the chart collection, so that we produce intensity data with the form: // - array indices (0,1,2,..., for each array) // - chart indices (TIndex, repeated for each array) // - array data (the TSample[] values in each array) using( var buffers = DataCollection.GetDataBuffers( decomposeOption ) ) { var indexData = (Buffer<TIndex>)buffers[0]; var arrayData = (Buffer<TSample[]>)buffers[1]; int size = indexData.Size; var arrayIndexBuffers = new Buffer<int>[size]; var chartIndexBuffers = new Buffer<TIndex>[size]; var arrayDataBuffers = new Buffer<TSample>[size]; for( int i = 0; i < size; ++i ) { TSample[] array = arrayData[i]; arrayIndexBuffers[i] = SequenceBufferPool.CreateIntervalBuffer( array.Length, Unit.None, 0, 1 ); chartIndexBuffers[i] = SequenceBufferPool.CreateConstantBuffer( array.Length, Unit.None, indexData[i] ); arrayDataBuffers[i] = BufferPool.Default.GetBuffer( array, Unit.None ); } using(new BufferCollection(arrayIndexBuffers.Concat<IBuffer>(chartIndexBuffers).Concat(arrayDataBuffers))) { var expandedBuffers = new BufferCollection( BufferPool.Join( arrayIndexBuffers, Unit.None ), BufferPool.Join( chartIndexBuffers, Unit.None ), BufferPool.Join( arrayDataBuffers, Unit.None ) ); if( MarkIndexData ?? true ) expandedBuffers[0].Traits.Add( IndexBufferTrait.Instance ); return expandedBuffers; } } } void IGraphDataCollection.LoadDataBuffers( IList<IBuffer> dimensionValues ) { throw new NotSupportedException( ); } #endregion }
Extending the example from M18436, you can use the collection this way:
public partial class MainWindow : Window { private const double Interval = 0.2; private readonly DispatcherTimer timer; private readonly VerticalIntensityChartCollection<double, double> chart = new VerticalIntensityChartCollection<double, double>( capacity: 25 ); public MainWindow( ) { InitializeComponent( ); // Initialize chart with data. chart.Append( 0, new double[0] ); // Tell graph about data, and interval. graph.DefaultVerticalInterval = Interval; graph.DataSource = chart; // Use a timer to update chart data. timer = new DispatcherTimer( TimeSpan.FromSeconds( 0.1 ), DispatcherPriority.Normal, OnTimerTick, Dispatcher ); } private void OnTimerTick( object sender, EventArgs e ) { // Add a new set of data after the previous point. var previous = chart[chart.Count - 1]; double x = previous.Index + Interval; int length = 3; double[] y = Enumerable.Repeat( x * 2.0, length ).Select( ( v, i ) => v + i ).ToArray( ); chart.Append( x, y ); } }
(Note that this simplified implementation does require every appended array to use the same length.)
04-24-2018 02:51 AM - edited 04-24-2018 02:52 AM
Thank you Paul,
You are the best.
Muhammed.
04-25-2018 02:50 AM
Hi Paul,
This is work properly.
We are working with MVVM pattern but we can't use binding method for VerticalIntenstyChartCollection.
When we define chart inside view model and bind it to Intensity Graph we get the attached error.
How to bind VerticalIntenstyChartCollection to graph?
Thank you very much,
Muhammed,
04-25-2018 09:54 AM
From the code I can see in the screenshot, it appears you have everything setup correctly on the graph side. I cannot see the definition of the chart type in that screenshot: does it still have the DataTypeDescriptor
attribute at the top?
04-26-2018 05:02 AM
Thanks Paul.
We added DataTypeDescriptor and its working.
Our mistake .