Пример #1
0
 /// <summary>
 /// Create a new <see cref="ExportedSeries"/> instance.
 /// </summary>
 /// <param name="series">The actual series.</param>
 /// <param name="xAxisRequirements">X axis requirements of the series.</param>
 /// <param name="yAxisRequirements">Y axis requirements of the series.</param>
 /// <param name="labels">Axis labels required by the series.</param>
 public ExportedSeries(Series series, AxisRequirements xAxisRequirements, AxisRequirements yAxisRequirements, AxisLabelCollection labels)
 {
     Result            = series;
     XAxisRequirements = xAxisRequirements;
     YAxisRequirements = yAxisRequirements;
     AxisLabels        = labels;
 }
Пример #2
0
        /// <summary>
        /// Export the line series to an oxyplot series.
        /// </summary>
        /// <param name="series">The line series to be exported.</param>
        /// <param name="labels">Existing axis labels.</param>
        protected override (Series, AxisLabelCollection) Export(LineSeries series, AxisLabelCollection labels)
        {
            LineSeriesWithTracker result = new LineSeriesWithTracker();
            DataPointCollection   data   = GetDataPoints(series.X, series.Y, labels);

            result.ItemsSource = data.Points;

            if (series.ShowOnLegend)
            {
                result.Title = series.Title;
            }

            // Line style/thickness
            result.LineStyle       = series.LineConfig.Type.ToOxyPlotLineStyle();
            result.StrokeThickness = series.LineConfig.Thickness.ToOxyPlotThickness();
            // tbi: line colour configuration
            // result.Stroke = series.LineConfig.Colour.ToOxyPlotColour();

            // Marker type/thickness
            result.MarkerType = series.MarkerConfig.Type.ToOxyPlotMarkerType();
            result.MarkerSize = series.MarkerConfig.Size.ToOxyPlotMarkerSize() * series.MarkerConfig.SizeModifier;
            if (series.MarkerConfig.IsFilled())
            {
                result.MarkerFill = series.Colour.ToOxyColour();
            }
            else
            {
                result.MarkerFill = OxyColors.Undefined;
            }

            // Colour
            result.Color = series.Colour.ToOxyColour();
            return(result, data.Labels);
        }
Пример #3
0
        /// <summary>
        /// Export the error series to an oxyplot series.
        /// </summary>
        /// <param name="series">The error series to be exported.</param>
        /// <param name="labels">Existing axis labels on the graph.</param>
        protected override (Series, AxisLabelCollection) Export(ErrorSeries series, AxisLabelCollection labels)
        {
            var result = new OxyPlot.Series.ScatterErrorSeries();

            (result.ItemsSource, labels) = GetErrorDataPoints(series.X, series.Y, series.XError, series.YError, labels);
            if (series.ShowOnLegend)
            {
                result.Title = series.Title;
            }

            // Line style/thickness
            // tbi: line colour configuration
            // result.Stroke = series.LineConfig.Colour.ToOxyPlotColour();

            // Marker type/thickness
            // fixme - this is all duplicated from LineSeries.
            result.MarkerType = series.MarkerConfig.Type.ToOxyPlotMarkerType();
            result.MarkerSize = series.MarkerConfig.Size.ToOxyPlotMarkerSize() * series.MarkerConfig.SizeModifier;
            if (series.MarkerConfig.IsFilled())
            {
                result.MarkerFill = series.Colour.ToOxyColour();
            }

            result.ErrorBarStrokeThickness = series.BarThickness.ToOxyPlotThickness();
            // TBI: stopper thickness

            // Colour
            result.ErrorBarColor = series.Colour.ToOxyColour();

            return(result, labels);
        }
Пример #4
0
        /// <summary>
        /// Export the series to an oxyplot series.
        /// </summary>
        /// <remarks>
        /// When dealing with string data, the returned data points are ints
        /// which are indices into the axis labels list. Therefore we
        /// need to know about any existing axis labels.
        /// </remarks>
        /// <param name="series">The series to be exported.</param>
        /// <param name="existingAxisLabels">Existing axis labels on the graph.</param>
        public ExportedSeries Export(ISeries series, AxisLabelCollection existingAxisLabels)
        {
            (Series oxyPlotSeries, AxisLabelCollection labels) = Export((T)series, existingAxisLabels);

            AxisType?xAxisType = GetRequiredAxisType(series.X.FirstOrDefault());
            AxisType?yAxisType = GetRequiredAxisType(series.Y.FirstOrDefault());

            AxisRequirements xAxisRequirements = new AxisRequirements(xAxisType, series.XFieldName);
            AxisRequirements yAxisRequirements = new AxisRequirements(yAxisType, series.YFieldName);

            return(new ExportedSeries(oxyPlotSeries, xAxisRequirements, yAxisRequirements, labels));
        }
Пример #5
0
        /// <summary>
        /// Export the bar series to an oxyplot series.
        /// </summary>
        /// <param name="series">The bar series to be exported.</param>
        /// <param name="labels">Existing axis labels.</param>
        protected override (Series, AxisLabelCollection) Export(BarSeries series, AxisLabelCollection labels)
        {
            ColumnXYSeries result = new ColumnXYSeries();

            if (series.ShowOnLegend)
            {
                result.Title = series.Title;
            }

            result.FillColor   = series.FillColour.ToOxyColour();
            result.StrokeColor = series.Colour.ToOxyColour();

            DataPointCollection data = GetDataPoints(series.X, series.Y, labels);

            result.ItemsSource = data.Points;

            return(result, data.Labels);
        }
Пример #6
0
        private (IList <BoxPlotItem>, AxisLabelCollection) GetBoxPlotItems(BoxWhiskerSeries series, AxisLabelCollection labels)
        {
            List <string>        yLabels = labels.YLabels.ToList();
            IEnumerable <double> y       = series.Y.Select(yi => GetDataPointValue(yi, yLabels));

            labels = new AxisLabelCollection(labels.XLabels, yLabels);

            double[] fiveNumberSummary = y.FiveNumberSummary();
            double   min           = fiveNumberSummary[0];
            double   lowerQuartile = fiveNumberSummary[1];
            double   median        = fiveNumberSummary[2];
            double   upperQuartile = fiveNumberSummary[3];
            double   max           = fiveNumberSummary[4];

            // fixme - this won't work with multiple box plot series on the same graph.
            double x = 0;

            IList <BoxPlotItem> items = new List <BoxPlotItem>()
            {
                new BoxPlotItem(x, min, lowerQuartile, median, upperQuartile, max)
            };

            return(items, labels);
        }
Пример #7
0
        /// <summary>
        /// Export the box and whisker series to an oxyplot series.
        /// </summary>
        /// <param name="series">The box and whisker series to be exported.</param>
        /// <param name="labels">Existing axis labels.</param>
        /// <param name="labels">Existing axis labels.</param>
        protected override (Series, AxisLabelCollection) Export(BoxWhiskerSeries series, AxisLabelCollection labels)
        {
            BoxPlotSeries result = new BoxPlotSeries();

            (result.Items, labels) = GetBoxPlotItems(series, labels);
            if (series.ShowOnLegend)
            {
                result.Title = series.Title;
            }

            // Line style/thickness
            result.LineStyle       = series.LineConfig.Type.ToOxyPlotLineStyle();
            result.StrokeThickness = series.LineConfig.Thickness.ToOxyPlotThickness();
            // tbi: line colour configuration
            // result.Stroke = series.LineConfig.Colour.ToOxyPlotColour();

            // Marker type/thickness
            result.OutlierType = series.MarkerConfig.Type.ToOxyPlotMarkerType();
            result.OutlierSize = series.MarkerConfig.Size.ToOxyPlotMarkerSize() * series.MarkerConfig.SizeModifier;

            // Colour
            result.Stroke = OxyColors.Transparent;
            result.Fill   = series.Colour.ToOxyColour();

            // todo: need to account for the possibility of string datatypes here.
            return(result, labels);
        }
Пример #8
0
        /// <summary>
        /// Convert the given apsim graph to an oxyplot <see cref="PlotModel"/>.
        /// </summary>
        /// <param name="graph">The graph to be converted.</param>
        public IPlotModel ToPlotModel(IGraph graph)
        {
            if (graph.XAxis == null)
            {
                throw new NullReferenceException("Graph has no x-axis");
            }
            if (graph.YAxis == null)
            {
                throw new NullReferenceException("Graph has no y-axis");
            }
            if (graph.Legend == null)
            {
                throw new NullReferenceException("Graph has no legend configuration");
            }
            if (graph.Series == null)
            {
                throw new NullReferenceException("Graph has no series");
            }

            PlotModel plot = new PlotModel();

            // Add series to graph.
            AxisLabelCollection labels            = AxisLabelCollection.Empty();
            ExportedSeries      previous          = null;
            AxisRequirements    xAxisRequirements = null;
            AxisRequirements    yAxisRequirements = null;

            foreach (Series graphSeries in graph.Series)
            {
                ExportedSeries series = graphSeries.ToOxyPlotSeries(labels);
                labels = series.AxisLabels;
                plot.Series.Add(series.Result);
                if (previous == null)
                {
                    previous = series;
                }
                else
                {
                    previous.ThrowIfIncompatibleWith(series);
                    previous = series;
                }
                if (series.XAxisRequirements.AxisKind != null)
                {
                    xAxisRequirements = series.XAxisRequirements;
                }
                if (series.YAxisRequirements.AxisKind != null)
                {
                    yAxisRequirements = series.YAxisRequirements;
                }
            }

            // Axes (don't add them if there are no series to display on the graph).
            if (xAxisRequirements?.AxisKind != null)
            {
                plot.Axes.Add(graph.XAxis.ToOxyPlotAxis(xAxisRequirements, labels.XLabels));
            }
            if (yAxisRequirements?.AxisKind != null)
            {
                plot.Axes.Add(graph.YAxis.ToOxyPlotAxis(yAxisRequirements, labels.YLabels));
            }

            // Legend

            plot.Legends.Add(new Legend()
            {
                LegendOrientation = graph.Legend.Orientation.ToOxyPlotLegendOrientation(),
                LegendPosition    = graph.Legend.Position.ToOxyPlotLegendPosition(),
                LegendPlacement   = graph.Legend.InsideGraphArea ? OxyLegendPlacement.Inside : OxyLegendPlacement.Outside,
                Font = font,
            });


            // Apply font
            plot.TitleFont = font;
            plot.SetLegendFont(font);
            plot.PlotAreaBorderThickness = new OxyThickness(0);
            plot.Title = graph.Title;

            return(plot);
        }
Пример #9
0
        /// <summary>
        /// Get error points.
        /// </summary>
        /// <param name="x">X data.</param>
        /// <param name="y">Y data.</param>
        /// <param name="xError">X error data.</param>
        /// <param name="yError">Y error data.</param>
        /// <param name="labels">Existing axis labels on the graph.</param>
        private (IEnumerable <ScatterErrorPoint>, AxisLabelCollection) GetErrorDataPoints(IEnumerable <object> x, IEnumerable <object> y, IEnumerable <object> xError, IEnumerable <object> yError, AxisLabelCollection labels)
        {
            List <string> xLabels = labels.XLabels.ToList();
            List <string> yLabels = labels.YLabels.ToList();

            List <double> xValues      = x.Select(xi => GetDataPointValue(xi, xLabels)).ToList();
            List <double> yValues      = y.Select(yi => GetDataPointValue(yi, yLabels)).ToList();
            List <double> xErrorValues = xError.Select(xi => GetDataPointValue(xi, xLabels)).ToList();
            List <double> yErrorValues = yError.Select(yi => GetDataPointValue(yi, yLabels)).ToList();

            labels = new AxisLabelCollection(xLabels, yLabels);

            if (xValues.Count == yValues.Count)
            {
                if (xValues.Count == xErrorValues.Count && xValues.Count == yErrorValues.Count)
                {
                    // We have error data for both x and y series.
                    List <ScatterErrorPoint> points = new List <ScatterErrorPoint>();
                    for (int i = 0; i < xValues.Count; i++)
                    {
                        if (!double.IsNaN(xValues[i]) && !double.IsNaN(yValues[i]) && !double.IsNaN(xErrorValues[i]) && !double.IsNaN(yErrorValues[i]))
                        {
                            points.Add(new ScatterErrorPoint(xValues[i], yValues[i], xErrorValues[i], yErrorValues[i], 0));
                        }
                    }
                    return(points, labels);
                }
                else if (xValues.Count == xErrorValues.Count)
                {
                    if (yErrorValues.Count != 0)
                    {
                        throw new ArgumentException($"Number of y error values ({yErrorValues.Count}) does not match number of datapoints or x error values ({xValues.Count})");
                    }
                    // We have error data for x series.
                    List <ScatterErrorPoint> points = new List <ScatterErrorPoint>();
                    for (int i = 0; i < xValues.Count; i++)
                    {
                        if (!double.IsNaN(xValues[i]) && !double.IsNaN(yValues[i]) && !double.IsNaN(xErrorValues[i]))
                        {
                            points.Add(new ScatterErrorPoint(xValues[i], yValues[i], xErrorValues[i], 0, 0));
                        }
                    }
                    return(points, labels);
                }
                else if (yValues.Count == yErrorValues.Count)
                {
                    if (xErrorValues.Count != 0)
                    {
                        throw new ArgumentException($"Number of x error values ({xErrorValues.Count}) does not match number of datapoints or y error values ({xValues.Count})");
                    }
                    // We have error data for y series.
                    List <ScatterErrorPoint> points = new List <ScatterErrorPoint>();
                    for (int i = 0; i < xValues.Count; i++)
                    {
                        if (!double.IsNaN(xValues[i]) && !double.IsNaN(yValues[i]) && !double.IsNaN(yErrorValues[i]))
                        {
                            points.Add(new ScatterErrorPoint(xValues[i], yValues[i], 0, yErrorValues[i], 0));
                        }
                    }
                    return(points, labels);
                }
                else
                {
                    // Throw error if we have nonzero x or y error data,
                    // but the number of items doesn't match.
                    if (xErrorValues.Count != 0)
                    {
                        if (yErrorValues.Count != 0)
                        {
                            throw new ArgumentException($"Number of x/y pairs ({xValues.Count}) does not match number of x error values ({xErrorValues.Count}) or number of y error values ({yErrorValues.Count})");
                        }
                        throw new ArgumentException($"Number of x/y pairs ({xValues.Count}) does not match number of x error values ({xErrorValues.Count})");
                    }
                    if (yErrorValues.Count != 0)
                    {
                        throw new ArgumentException($"Number of x/y pairs ({xValues.Count}) does not match number of y error values ({yErrorValues.Count})");
                    }

                    // If we reached here, there is no x or y error values.
                    // This raises the question of why this series is an error series
                    // given that there's no error data. The most likely cause is a
                    // programming error. However, we might as well just treat it as a
                    // normal series and plot the x/y data anyway.
                    IEnumerable <ScatterErrorPoint> points = xValues.Zip(yValues, (xi, yi) => new ScatterErrorPoint(xi, yi, 0, 0));
                    return(points, labels);
                }
            }
            else
            {
                throw new ArgumentException($"X and Y series are of different lengths ({xValues.Count} vs {yValues.Count})");
            }
        }
Пример #10
0
        /// <summary>
        /// fixme: use classes for different data types
        /// </summary>
        /// <remarks>
        /// When dealing with string data, the returned data points are ints
        /// which are indices into the axis labels list. Therefore we
        /// need to know about any existing axis labels.
        /// </remarks>
        /// <param name="x"></param>
        /// <param name="y"></param>
        protected DataPointCollection GetDataPoints(IEnumerable <object> x, IEnumerable <object> y, AxisLabelCollection existingAxisLabels)
        {
            if (x == null)
            {
                throw new ArgumentNullException("x data is null");
            }
            if (y == null)
            {
                throw new ArgumentNullException("y data is null");
            }

            List <DataPoint> data        = new List <DataPoint>();
            List <string>    xAxisLabels = existingAxisLabels.XLabels.ToList();
            List <string>    yAxisLabels = existingAxisLabels.YLabels.ToList();


            foreach ((object xi, object yi) in x.Zip(y))
            {
                data.Add(new DataPoint(GetDataPointValue(xi, xAxisLabels), GetDataPointValue(yi, yAxisLabels)));
            }

            return(new DataPointCollection(data, xAxisLabels, yAxisLabels));
        }
Пример #11
0
 /// <summary>
 /// Export the series to an oxyplot series.
 /// </summary>
 /// <param name="series">The series to be exported.</param>
 protected abstract (Series, AxisLabelCollection) Export(T series, AxisLabelCollection existingAxisLabels);
Пример #12
0
 /// <summary>
 /// Create a new <see cref="DataPointCollection"/> instance.
 /// </summary>
 /// <param name="dataPoints">The data points.</param>
 /// <param name="xLabels">The x-axis labels.</param>
 /// <param name="yLabels">The y-axis labels.</param>
 public DataPointCollection(IEnumerable <DataPoint> dataPoints, IEnumerable <string> xLabels, IEnumerable <string> yLabels)
 {
     Points = dataPoints;
     Labels = new AxisLabelCollection(xLabels, yLabels);
 }
Пример #13
0
        /// <summary>
        /// Convert an apsim series to an oxyplot series.
        /// </summary>
        /// <remarks>
        /// When dealing with string data, the returned data points are ints
        /// which are indices into the axis labels list. Therefore we
        /// need to know about any existing axis labels.
        /// </remarks>
        /// <param name="series">The series to be converted.</param>
        /// <param name="labels">Existing axis labels on the graph.</param>
        public static ExportedSeries ToOxyPlotSeries(this APSIM.Shared.Graphing.Series series, AxisLabelCollection labels)
        {
            ISeriesExporter exporter = FindSeriesExporter(series);

            return(exporter.Export(series, labels));
        }
Пример #14
0
 /// <summary>
 /// Export the region series to an oxyplot series.
 /// </summary>
 /// <param name="series">The region series to be exported.</param>
 /// <param name="labels">Existing axis labels.</param>
 protected override (Series, AxisLabelCollection) Export(RegionSeries series, AxisLabelCollection labels)
 {
     throw new NotImplementedException();
 }