3

I've been playing around with trying to plot a boxplot using Oxyplot in WPF. I've managed to get a nice graph working in a completely new project, and am now attempting to show a similar graph in a new window of a project I'm currently working on and I'm not managing to get anything to show up. It's probably something very obvious, but I'm a bit lost. Here's where I'm at.

New Window I'm trying to open:
XAML

<Window x:Class="Data_Mining_Over_Cancer_Data.DistancePlots"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:oxy="http://oxyplot.org/wpf"
    xmlns:local="clr-namespace:Data_Mining_Over_Cancer_Data"
    mc:Ignorable="d"
    Title="DistancePlots" Height="300" Width="300">
<Window.DataContext>
    <local:DistancePlots/>
</Window.DataContext>
<Grid>
    <oxy:PlotView Model="{Binding MyModel}"/>
</Grid>

Code

 /// </summary>
public partial class DistancePlots : Window
{
    public DistancePlots()
    {
        //InitializeComponent();
        DistanceBoxPlotSeries plots = new DistanceBoxPlotSeries();
        this.MyModel = plots.CreateBoxPlot();            
    }
    public PlotModel MyModel { get; private set; }
}
public class Item
{
    #region Public Properties

    public string Label { get; set; }

    #endregion Public Properties
}

public class DistanceBoxPlotSeries
{
    #region Public Constructors

    public DistanceBoxPlotSeries()
    {
    }

    #endregion Public Constructors

    #region Public Methods

    public PlotModel CreateBoxPlot()
    {
        const int boxes = 4;
        var plot = new PlotModel();
        var items = new Collection<Item>();

        for (int i = 1; i < boxes + 1; i++)
        {
            items.Add(new Item { Label = i.ToString() });
        }

        plot.Axes.Add(new LinearAxis
        {
            Position = AxisPosition.Left,
            MajorStep = 1,
            MinorStep = 0.25,
            TickStyle = TickStyle.Crossing,
            AbsoluteMaximum = 5.25,
            AbsoluteMinimum = -0.25
        });

        plot.Axes.Add(new CategoryAxis
        {
            Position = AxisPosition.Bottom,
            ItemsSource = items,
            LabelField = "Label",
            IsTickCentered = true,
            TickStyle = TickStyle.None,
            AbsoluteMinimum = -1,
            AbsoluteMaximum = 17,
            IsZoomEnabled = false
        });

        var lineAnnotation = new LineAnnotation
        {
            Type = LineAnnotationType.Horizontal,
            Y = 5,
            LineStyle = LineStyle.Dash,
            StrokeThickness = 2,
            Color = OxyColor.FromArgb(50, 0, 0, 0)
        };
        plot.Annotations.Add(lineAnnotation);

        lineAnnotation = new LineAnnotation
        {
            Type = LineAnnotationType.Horizontal,
            Y = 1,
            LineStyle = LineStyle.Dash,
            StrokeThickness = 1.5,
            Color = OxyColor.FromArgb(50, 0, 0, 0)
        };
        plot.Annotations.Add(lineAnnotation);

        lineAnnotation = new LineAnnotation
        {
            Type = LineAnnotationType.Horizontal,
            Y = 4,
            LineStyle = LineStyle.Solid,
            StrokeThickness = 1.5,
            Color = OxyColor.FromArgb(50, 0, 0, 0)
        };
        plot.Annotations.Add(lineAnnotation);

        lineAnnotation = new LineAnnotation
        {
            Type = LineAnnotationType.Horizontal,
            Y = 2,
            LineStyle = LineStyle.Solid,
            StrokeThickness = 1.5,
            Color = OxyColor.FromArgb(50, 0, 0, 0)
        };
        plot.Annotations.Add(lineAnnotation);

        var s1 = new BoxPlotSeries();
        s1.Fill = OxyColor.FromRgb(0x1e, 0xb4, 0xda);
        s1.StrokeThickness = 1.1;
        s1.WhiskerWidth = 1;
        var random = new Random();
        for (int i = 0; i < boxes; i++)
        {
            double x = i;
            var points = 5 + random.Next(15);
            var values = new List<double>();
            for (int j = 0; j < points; j++)
            {
                values.Add((random.NextDouble()) * 5);
            }

            values.Sort();
            var median = getMedian(values);
            int r = values.Count % 2;
            double firstQuartil = getMedian(values.Take((values.Count + r) / 2)); // 25%-Quartil
            double thirdQuartil = getMedian(values.Skip((values.Count - r) / 2)); // 75%-Quartil

            var iqr = thirdQuartil - firstQuartil; // Quartilabstand
            var step = 1.5 * iqr;
            var upperWhisker = thirdQuartil + step;
            upperWhisker = values.Where(v => v <= upperWhisker).Max();
            var lowerWhisker = firstQuartil - step;
            lowerWhisker = values.Where(v => v >= lowerWhisker).Min();
            var outliers = values.Where(v => v > upperWhisker || v < lowerWhisker).ToList();

            s1.Items.Add(new BoxPlotItem(x, lowerWhisker, firstQuartil, median, thirdQuartil, upperWhisker));
        }

        plot.Series.Add(s1);
        return plot;
    }

    #endregion Public Methods

    #region Private Methods

    private static double getMedian(IEnumerable<double> values)
    {
        var sortedInterval = new List<double>(values);
        sortedInterval.Sort();
        var count = sortedInterval.Count;
        if (count % 2 == 1)
        {
            return sortedInterval[(count - 1) / 2];
        }

        return 0.5 * sortedInterval[count / 2] + 0.5 * sortedInterval[(count / 2) - 1];
    }

    #endregion Private Methods
}

Opening the new window from the main window:

 private void PlotButton_Click(object sender, RoutedEventArgs e)
    {
        DistancePlots plots = new DistancePlots();
        plots.Show();
    }

Currently this opens the new window, but the graph isn't showing up. If I use the exact same code in the main window of a project, it works. My understanding of WPF data binding is quite limited, so I think something could be going wrong there?
Any help would be greatly appreciated. Cheers

jsanalytics
  • 13,058
  • 4
  • 22
  • 43
Daniel Whettam
  • 345
  • 1
  • 2
  • 9
  • 1) The `DataContext` for `DistancePlot` cannot be `DistancePlot`, that's going to cause stack over flow exception. 2) Because you did not define a view model the `DataContext` must be set to `this`. 3) Un-comment `InitializeComponent()` back in, you shouldn't remove that. – jsanalytics Mar 02 '18 at 21:37
  • 1
    @jsanalytics That works, thank you! I thought the data context wasn't right, but I wasn't sure what to set it to. – Daniel Whettam Mar 03 '18 at 14:16

0 Answers0