mapping vertical axis value with horizontal time axis

Apr 14, 2009 at 11:52 AM

Hi I am trying to develope a value - time plot. The mapping should be like this

const int N = 20;

double[] y = new double[N];

DateTime[] date = new DateTime[N];

for (int i = 0; i < N; i++)

{

y[i] = 0.1*i;

date[i] = DateTime.Now.AddMinutes(-20 + i);

}

I used HorizontalDateTimeAxis, The coding I made is

var yDataSource = new EnumerableDataSource<double>(y);

yDataSource.SetYMapping(Y => Y);

yDataSource.AddMapping(ShapeElementPointMarker.ToolTipTextProperty,

Y => string.Format("Value is {0}", Y));

var xDataSource = new EnumerableDataSource<DateTime>(date);

xDataSource.SetYMapping(X => TimeSpan.FromTicks(X.Date.Ticks).TotalMinutes);

xDataSource.AddMapping(ShapeElementPointMarker.ToolTipTextProperty, X => string.Format("Value is {0}", X));

plot.AddLineGraph(compositeDataSource, new Pen(Brushes.Goldenrod, 3), new StdDevMarker(), new PenDescription("Trend"));

axis.ConvertToDouble = dt => TimeSpan.FromTicks(dt.Ticks).TotalMinutes;

axis.ConvertFromDouble = d => new DateTime(TimeSpan.FromMinutes(d).Minutes);

Can anybody explain how to do mapping and when to use FromTicks , FromMinutes, FromDays etc.


Regards
Ravi. 

Apr 15, 2009 at 7:23 AM

Hi

For this mapping problem I tried using HorizontalTimeSpanAxis, With this I got the proper X(horizontal time axis) , But again Y axis( Values) are not mapped properly. ( I got the wrong plot)

 

Here I am pasting my code. Please show how to map times and corresponding values.

 

private void Hour1_Click(object sender, RoutedEventArgs e)

{

            const int N = 60;

            double[] x = new double[N];

            double[] y = new double[N];

            DateTime[] date = new DateTime[N];

            HorizontalTimeSpanAxis axis = new HorizontalTimeSpanAxis();

            Color[] colors = ColorHelper.CreateRandomColors(5);

 

            for (int i = 0; i < N; i++)

            {

                x[i] = i * 0.1;

                y[i] = x[i];// Math.Sin(x[i]);

                date[i] = DateTime.Now.AddMinutes(-60 + i);

            }

double minX = axis.ConvertToDouble(date[0].TimeOfDay);

            double maxX = axis.ConvertToDouble(date[N - 1].TimeOfDay);

            TimeSpanTicksProvider ticksProvider = (TimeSpanTicksProvider)axis.TicksProvider;

 

            // changing ticks calculating strategy to prefer separation on hours

ticksProvider.Strategy = new DelegateDateTimeStrategy((span) =>

            {

                if (span.TotalMinutes > 10 && span.TotalHours < 2)

                    return DifferenceIn.Minute;

                else if (span.TotalHours > 2 && span.TotalDays < 48)

                    return DifferenceIn.Hour;

                else if (span.TotalDays > 2 && span.TotalDays < 31)

                    return DifferenceIn.Day;

                else if (span.TotalDays > 31 && span.TotalDays < 365)

                    return DifferenceIn.Month;

                else if (span.TotalDays > 365)

                    return DifferenceIn.Year;

                // null makes to use base class return value

                return null;

            });

 

            TrendData = LoadTrendValues(date, y);

            TrendData = LoadTrendValues(date, y);

            if (currentgraph != null)

                plot.Children.Remove(currentgraph);

            else

                currentgraph = plot.AddLineGraph(CreateTrendDataSource(TrendData), colors[2], 1, "Trend");

            axis.ContentStringFormat = "dd/mm/yyyy";

            plot.HorizontalAxis = axis;

 

 

            Rect visible = plot.Viewport.Visible;

            visible.X = minX;

            visible.Width = maxX - minX;

 

            plot.Viewport.Visible = visible;

  }

 

private static List<TrendValueInfo> LoadTrendValues(DateTime[]  trendtimes, double[] trendvalues)

{

            var res = new List<TrendValueInfo>(trendvalues.Length - 1);

            for (int i = 0; i < trendvalues.Length; i++)

            {

                double value = trendvalues[i];

                DateTime date =trendtimes[i];

          res.Add(new TrendValueInfo { Date = date, Value =     value});

            }

 

            return res;

}

 

private EnumerableDataSource<TrendValueInfo>  CreateTrendDataSource(List<TrendValueInfo> trenddata)

{

            EnumerableDataSource<TrendValueInfo> ds = new EnumerableDataSource<TrendValueInfo>(trenddata);

            ds.SetXMapping(ci => TimeSpan.FromTicks(ci.Date.Ticks).Minutes);

            ds.SetYMapping(ci => ci.Value);

            return ds;

}

 

 

 

With this I got the time axis  as what I expected, But values( graph points are completely worng, It should plot as stringh ling ranging from 60 mins previous time to current time.

 

How change X aixs lable ( X axis annotation fromat string – I don’t what the name of this here) to the custom format like “ dd/MM/yyyy  hh:mm:ss” – some thing like this

 

Regards,

Ravi

 

Editor
Apr 16, 2009 at 1:14 PM
Hi Ravi,

I hope it will be helpful to you.

Seems like using that answer, you'll get what you want, and it will be simplier than the way you are trying to do it.

Regards,
Mikhail Brinchuk,
DynamicDataDisplay Dev Team.
Editor
Apr 16, 2009 at 1:16 PM
Hi Ravi,
You've asked:
How change X aixs lable ( X axis annotation fromat string – I don’t what the name of this here) to the custom format like “ dd/MM/yyyy  hh:mm:ss” – some thing like this?

Currently it is not possible to do it outside of DynamicDataDisplay (from your code), but it will be possible to do it in the next upcoming version of DynamicDataDisplay.

Mikhail.
Nov 23, 2009 at 4:19 PM

Hi Mikhail,

Is it possible now? I would like to show seconds on the HorizontalDateTimeAxis...

I'm using the trunk version.

André Carlucci

Nov 23, 2009 at 7:00 PM
Edited Nov 23, 2009 at 7:02 PM

I made some progress, but still coudn't make this right. I have a timeserie of 10 seconds, 60 values per second.

I created a custom HorizontalDateTimeAxis, like this:

public class CustomHorizontalDateTimeAxis : HorizontalDateTimeAxis {

        public CustomHorizontalDateTimeAxis() : base() {
            this.AxisControl.MayorLabelProvider.SetCustomFormatter(i => {
                return i.Tick.ToString("HH:mm:ss.fff");
            });

            this.ConvertFromDouble = ConvertFromDoubleFunction;
            this.ConvertToDouble = ConvertToDoubleFunction;
        }

        public static Func<DateTime, double> ConvertToDoubleFunction {
            get {
                return (dt) => { 
                    return dt.ToOADate();
                };
            }
        }

        public static Func<double, DateTime> ConvertFromDoubleFunction {
            get {
                return (d) => { 
                    return DateTime.FromOADate(d); 
                };
            }
        }
    }
Then I create my CompositeDataSource like this:
 
protected CompositeDataSource GetCompositeDataSource(int key) {
            List<double> y = _loadedData[key].Select(p => Convert.ToDouble(p.Value)).ToList();
            List<DateTime> x = _loadedData[key].Select(p => p.Time).ToList();

            EnumerableDataSource<double> ys = new EnumerableDataSource<double>(y);
            EnumerableDataSource<DateTime> xs = new EnumerableDataSource<DateTime>(x);
            
            ys.SetYMapping(py => py);
            xs.SetXMapping(CustomHorizontalDateTimeAxis.ConvertToDoubleFunction);

            return new CompositeDataSource(ys, xs);
        }
But the Chart is not showing the data correctly, the HorizontalDateTimeAxis shows the dateTime label in a different scale comparing 
to the original data. 
The seconds/milli are always 00.000 too.
 
I also tried using the original ConvertTo/FromDouble functions but it didn't work as well. 
Ex: 
long ticks = (long)(d * 10000000000L); ...
dt => dt.Ticks / 10000000000.0 ...
Any thoughts?
Thanks in advance,
André Carlucci