SciChart® the market leader in Fast WPF Charts, WPF 3D Charts, and now iOS Charting & Android Chart Components

Welcome to the SciChart Community Forums!

Please use the forums below to ask questions about SciChart. Take a moment to read our Question asking guidelines on how to ask a good question and our support policy. We also have a tag=SciChart on Stackoverflow.com where you can earn rep for your questions!

Please note: SciChart team will only answer questions from customers with active support subscriptions. Expired support questions will be ignored. If your support status shows incorrectly, contact us and we will be glad to help.

1
0

I am trying to use the Box plot type to render a gantt-style chart. The intention is to set the Median, lowerQuartile and Min all to the start time values, and the upperQuartile and Max to the End times.

The trouble, as I think I have found, is that the model doesn’t support DateTime as the type for the YAxis values. Using the Box Chart example in the demo suite for inspiration, I have two very stripped down charts on my page:

 <s:SciChartSurface x:Name="ganttChart" BorderThickness="0" Padding="0" Grid.Row="0">
      <s:SciChartSurface.RenderableSeries>
           <s:FastBoxPlotRenderableSeries x:Name="ganttSeries" />
      </s:SciChartSurface.RenderableSeries>
      <s:SciChartSurface.XAxis>
           <s:NumericAxis/>
      </s:SciChartSurface.XAxis>
      <s:SciChartSurface.YAxis>
           <s:DateTimeAxis/>
      </s:SciChartSurface.YAxis>
 </s:SciChartSurface>

 <s:SciChartSurface x:Name="sciChart" Grid.Column="1" BorderThickness="0" Padding="0" Grid.Row="1">
      <s:SciChartSurface.RenderableSeries>
           <s:FastBoxPlotRenderableSeries x:Name="boxSeries" />
      </s:SciChartSurface.RenderableSeries>
      <s:SciChartSurface.XAxis>
           <s:DateTimeAxis />
      </s:SciChartSurface.XAxis>
      <s:SciChartSurface.YAxis>
           <s:NumericAxis />
      </s:SciChartSurface.YAxis>
 </s:SciChartSurface>

I then populate them appropriately:

    private void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        var ganttDataSeries = new BoxPlotDataSeries<double, DateTime>();
        var ganttData = GetGanttPlotData().ToArray();

        ganttSeries.DataSeries = ganttDataSeries;
        ganttDataSeries.Append(ganttData.Select(x => x.X),
                    ganttData.Select(x => x.Median),
                    ganttData.Select(x => x.Minimum),
                    ganttData.Select(x => x.LowerQuartile),
                    ganttData.Select(x => x.UpperQuartile),
                    ganttData.Select(x => x.Maximum));

        var boxData = GetBoxPlotData().ToArray(); // this is the same implementation as the demo 
        var boxDataSeries = new BoxPlotDataSeries<DateTime, double>();
        boxDataSeries.Append(boxData.Select(x => x.Date),
            boxData.Select(x => x.Median),
            boxData.Select(x => x.Minimum),
            boxData.Select(x => x.LowerQuartile),
            boxData.Select(x => x.UpperQuartile),
            boxData.Select(x => x.Maximum));

        boxSeries.DataSeries = boxDataSeries;
    }

    private IEnumerable<GanttPoint> GetGanttPlotData()
    {
        var xValues = Enumerable.Range(1, 10).ToArray();

        var random = new Random();

        for (int i = 0; i < 10; i++)
        {
            DateTime med = new DateTime(2016, 1, 1).AddDays(random.Next(31, 330));
            DateTime min = med.AddDays(-1 * random.Next(30));
            DateTime max = med.AddDays(random.Next(30));
            DateTime lower = min.AddDays((med - min).TotalDays * random.NextDouble());
            DateTime upper = max.AddDays(-1 * ((max - med).TotalDays * random.NextDouble()));

            Console.WriteLine($"Median:{med} Min:{min} Max:{max} Lower:{lower} Upper:{upper}");
            yield return new GanttPoint(xValues[i], min, lower, med, upper, max);
        }
    }

    private struct GanttPoint
    {
        public readonly double X;
        public readonly DateTime Minimum;
        public readonly DateTime LowerQuartile;
        public readonly DateTime Median;
        public readonly DateTime UpperQuartile;
        public readonly DateTime Maximum;

        public GanttPoint(double x, DateTime min, DateTime lower, DateTime med, DateTime upper, DateTime max)
            : this()
        {
            X = x;
            Minimum = min;
            LowerQuartile = lower;
            Median = med;
            UpperQuartile = upper;
            Maximum = max;
        }
    }

The attached image is what renders. Is there a reason for this behavior? I was really hoping to use this plot type to support the floating bars use case. I can make a custom renderable series to achieve the result, but that seems like a lot of work.

Please advise.

Thanks,
Mike.

Version
4.1.0.8615
Images
  • Andrew
    Hi Mike, before we answer this question, would developing a custom renderable series be more suited to this task, rather than hacking an existing series? Alternatively, to rotate a chart, you don’t set YAxis with datetime values, but you instead rotate the chart as per https://www.scichart.com/wpf-chart-example-vertical-charts/
  • Michael Dusoe
    Yeah, I can get the horizontal lines, and that works fine. XAxis on the Left, YAxis on the Bottom – perfect. That is not the issue. Placing DateTime on the YAxis (whether on the bottom or the right) causes this behavior. I have considered a custom renderable, taking in a XyySeries, and drawing the boxes as approriate. I was just hoping to not have to go down that path. (Time to write Series + Time to write XAML) will always be greater than (Time to write XAML) :+) I have seen that some have implemented this as a collection of Box Annotations, but I am already looking at providing a pile of annotations (both native and custom) to interact with the data, and I would rather not have to manage “Data Annotations” separate from “Tool Annotations”, especially since they are all in a single collection for the Surface.
  • You must to post comments
1
0

For anyone who cares 🙂

I solved this by making the YAxis Numeric, of type long, instead of DateTime. I store the values as Ticks, and then use a simple LabelProvider like below to change the labels to dates:

public class GanttLabelProvider : NumericLabelProvider
{
    public override string FormatLabel(IComparable dataValue)
    {
        return new DateTime( Convert.ToInt64(dataValue)).ToString("yyyy/MM/dd hh:mm:ss.ffff");
    }
}

Runs like a champ!

  • You must to post comments
0
0

where to add this code snippet

  • You must to post comments
Showing 2 results
Your Answer

Please first to submit.