Measurement Studio for .NET Languages

cancel
Showing results for 
Search instead for 
Did you mean: 

Cheapest way to apply X-axis values in WPF

Solved!
Go to solution

Hello,

In my latest project I'm working with double[] arrays where I apply all kinds of filters to an entire array at once using a 3rd party library.  When it's time to plot the data, I don't have the correct X-axis values because I'm not using Point[] arrays (so X-axis is just 0 to N incremented by 1).

What is the "cheapest" way out of this?  I mean, I don't want to loop through the entire array (could be 20-30K long each * 32) and create Point objects out of doubles.  In MATLAB there's a way to simply assign a separate array to X-axis so I was wondering if there's something like this in NI Lib.

Thanks!

0 Kudos
Message 1 of 5
(3,175 Views)

For the WPF controls, we do have the ChartCollection<TIndexData,TSampleData> types for accumulating a history of data, but we do not have an equivalent collection type for plotted data. Assuming the chart collection will not work for your use case, there are two main approaches to displaying your data with custom index values:

  • Change how the values are displayed: This involves creating a custom value presenter that will interpret the “0,1,...,N” index values from the array as your domain values. This answer to another question would be a good starting point, depending on exactly how you want to display the values.
  • Change how the values are published: This involves creating a custom data type that our controls can recognize. The most direct way would be to implement the IGraphDataCollection interface.

It would be helpful to know what are “the correct X-axis values” you’re looking for, to give you more specific suggestions.

~ Paul H
0 Kudos
Message 2 of 5
(3,156 Views)

Hi Paul,

My Y-axis is Nano Tesla and my X-axis is seconds.  Seconds array is calculated by multiplying one of the data array by sample rate.  I hope this clarifies it.

Thanks

0 Kudos
Message 3 of 5
(3,150 Views)
Solution
Accepted by topic author kirko7

Based on your description, it sounds like you are reading values at a fixed sample rate. In that case, here are simple versions of each of the approaches above:

 

Custom value presenter for array data:

    public class CustomSampleRateFormatter : GeneralValueFormatter {

        public double Start { get; set; }
        public double Rate { get; set; }

        public CustomSampleRateFormatter( ) {
            Start = 0.0;
            Rate = 1.0;
        }

        protected override string FormatCore<TData>( TData value, ValuePresenterArgs args ) {
            double shiftedValue = Start + Convert.ToDouble( value ) * Rate;
            return base.FormatCore<double>( shiftedValue, args );
        }

        protected override Freezable CreateInstanceCore( ) {
            return new CustomSampleRateFormatter( );
        }

    }

 

Custom collection for publishing data:

    [DataTypeDescriptor( typeof( GraphDataCollectionDescriptor<> ) )]
    public class DataCollection<TData> : IGraphDataCollection {

        private double start;
        private double rate;
        private TData[] data;

        public DataCollection( ) {
            SetData( 0.0, 1.0, new TData[0] );
        }

        public void SetData( double start, double rate, TData[] data ) {
            this.start = start;
            this.rate = rate;
            this.data = data;

            DataChanged( this, new GraphCollectionChangedEventArgs( Count ) );
        }

        #region IGraphDataCollection Members

        private static readonly ReadOnlyCollection<Type> DataTypes = new ReadOnlyCollection<Type>( new[] { typeof( double ), typeof( TData ) } );

        public int Count { get { return this.data.Length; } }

        public bool? MarkIndexData { get; set; }

        public event EventHandler<GraphCollectionChangedEventArgs> DataChanged = delegate { };

        public ReadOnlyCollection<Type> GetDataTypes( ) { return DataTypes; }

        public BufferCollection GetDataBuffers( Trait decomposeOption ) {
            var indexData = SequenceBufferPool.CreateIntervalBuffer( Count, Unit.None, this.start, this.rate );
            var sampleData = BufferPool.Default.GetBuffer( this.data, Unit.None );

            if( MarkIndexData ?? true )
                indexData.Traits.Add( IndexBufferTrait.Instance );

            return new BufferCollection(indexData, sampleData);
        }

        void IGraphDataCollection.LoadDataBuffers( IList<IBuffer> dimensionValues ) { throw new NotSupportedException( ); }

        #endregion

    }

 

After testing them out, the custom data collection will probably be the most useful (all parts of the graph will recognize the domain of the incoming data, as opposed to just the displayed value on the scale). This is a bare-bones implementation, so feel free to customize it to better match your use case.

~ Paul H
Message 4 of 5
(3,141 Views)

Thank you, Paul.

Yes, it's a fixed sample rate.

I will try your suggestion sometime this week.

Thanks!

0 Kudos
Message 5 of 5
(3,138 Views)