Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PerformanceComparison/HeuristicLab.Analysis.Views/3.3/ScatterPlotView.cs @ 13722

Last change on this file since 13722 was 13722, checked in by abeham, 8 years ago

#2457:

  • Renamed remaining files from ExpertSystem to KnowledgeCenter
  • Added ability to scatter plot to display a regression line
  • Allowed to execute multiple instances at once and displaying either only final result or tracking result
  • Split runs in seeded runs and instance runs
File size: 23.7 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using HeuristicLab.Collections;
23using HeuristicLab.Common;
24using HeuristicLab.Core.Views;
25using HeuristicLab.MainForm;
26using System;
27using System.Collections.Generic;
28using System.Drawing;
29using System.Linq;
30using System.Windows.Forms;
31using System.Windows.Forms.DataVisualization.Charting;
32
33namespace HeuristicLab.Analysis.Views {
34  [View("ScatterPlot View")]
35  [Content(typeof(ScatterPlot), true)]
36  public partial class ScatterPlotView : NamedItemView, IConfigureableView {
37    protected List<Series> invisibleSeries;
38    protected Dictionary<IObservableList<Point2D<double>>, ScatterPlotDataRow> pointsRowsTable;
39    private double xMin, xMax, yMin, yMax;
40
41    public new ScatterPlot Content {
42      get { return (ScatterPlot)base.Content; }
43      set { base.Content = value; }
44    }
45
46    public ScatterPlotView() {
47      InitializeComponent();
48      pointsRowsTable = new Dictionary<IObservableList<Point2D<double>>, ScatterPlotDataRow>();
49      invisibleSeries = new List<Series>();
50      chart.CustomizeAllChartAreas();
51      chart.ChartAreas[0].CursorX.Interval = 1;
52    }
53
54    #region Event Handler Registration
55    protected override void DeregisterContentEvents() {
56      foreach (ScatterPlotDataRow row in Content.Rows)
57        DeregisterScatterPlotDataRowEvents(row);
58      Content.VisualPropertiesChanged -= new EventHandler(Content_VisualPropertiesChanged);
59      Content.Rows.ItemsAdded -= new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsAdded);
60      Content.Rows.ItemsRemoved -= new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsRemoved);
61      Content.Rows.ItemsReplaced -= new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsReplaced);
62      Content.Rows.CollectionReset -= new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_CollectionReset);
63      base.DeregisterContentEvents();
64    }
65    protected override void RegisterContentEvents() {
66      base.RegisterContentEvents();
67      Content.VisualPropertiesChanged += new EventHandler(Content_VisualPropertiesChanged);
68      Content.Rows.ItemsAdded += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsAdded);
69      Content.Rows.ItemsRemoved += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsRemoved);
70      Content.Rows.ItemsReplaced += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsReplaced);
71      Content.Rows.CollectionReset += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_CollectionReset);
72    }
73
74    protected virtual void RegisterScatterPlotDataRowEvents(ScatterPlotDataRow row) {
75      row.NameChanged += new EventHandler(Row_NameChanged);
76      row.VisualPropertiesChanged += new EventHandler(Row_VisualPropertiesChanged);
77      pointsRowsTable.Add(row.Points, row);
78      row.Points.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsAdded);
79      row.Points.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsRemoved);
80      row.Points.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsReplaced);
81      row.Points.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_CollectionReset);
82    }
83    protected virtual void DeregisterScatterPlotDataRowEvents(ScatterPlotDataRow row) {
84      row.Points.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsAdded);
85      row.Points.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsRemoved);
86      row.Points.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsReplaced);
87      row.Points.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_CollectionReset);
88      pointsRowsTable.Remove(row.Points);
89      row.VisualPropertiesChanged -= new EventHandler(Row_VisualPropertiesChanged);
90      row.NameChanged -= new EventHandler(Row_NameChanged);
91    }
92    #endregion
93
94    protected override void OnContentChanged() {
95      base.OnContentChanged();
96      invisibleSeries.Clear();
97      chart.Titles[0].Text = string.Empty;
98      chart.ChartAreas[0].AxisX.Title = string.Empty;
99      chart.ChartAreas[0].AxisY.Title = string.Empty;
100      chart.Series.Clear();
101      if (Content != null) {
102        chart.Titles[0].Text = Content.Name;
103        AddScatterPlotDataRows(Content.Rows);
104        ConfigureChartArea(chart.ChartAreas[0]);
105        RecalculateMinMaxPointValues();
106        RecalculateAxesScale(chart.ChartAreas[0]);
107      }
108    }
109
110    protected override void SetEnabledStateOfControls() {
111      base.SetEnabledStateOfControls();
112      chart.Enabled = Content != null;
113    }
114
115    public void ShowConfiguration() {
116      if (Content != null) {
117        using (ScatterPlotVisualPropertiesDialog dialog = new ScatterPlotVisualPropertiesDialog(Content)) {
118          dialog.ShowDialog(this);
119        }
120      } else MessageBox.Show("Nothing to configure.");
121    }
122
123    protected virtual void AddScatterPlotDataRows(IEnumerable<ScatterPlotDataRow> rows) {
124      foreach (var row in rows) {
125        RegisterScatterPlotDataRowEvents(row);
126        Series series = new Series(row.Name);
127        if (row.VisualProperties.DisplayName.Trim() != String.Empty) series.LegendText = row.VisualProperties.DisplayName;
128        else series.LegendText = row.Name;
129        ConfigureSeries(series, row);
130        FillSeriesWithRowValues(series, row);
131        chart.Series.Add(series);
132      }
133      ConfigureChartArea(chart.ChartAreas[0]);
134      RecalculateMinMaxPointValues();
135      RecalculateAxesScale(chart.ChartAreas[0]);
136      UpdateYCursorInterval();
137    }
138
139    protected virtual void RemoveScatterPlotDataRows(IEnumerable<ScatterPlotDataRow> rows) {
140      foreach (var row in rows) {
141        DeregisterScatterPlotDataRowEvents(row);
142        Series series = chart.Series[row.Name];
143        if (chart.Series.IsUniqueName(series.Name + ".lr"))
144          chart.Series.Remove(chart.Series[series.Name + ".lr"]);
145        chart.Series.Remove(series);
146        if (invisibleSeries.Contains(series))
147          invisibleSeries.Remove(series);
148      }
149      RecalculateMinMaxPointValues();
150      RecalculateAxesScale(chart.ChartAreas[0]);
151    }
152
153    private void ConfigureSeries(Series series, ScatterPlotDataRow row) {
154      series.BorderWidth = 1;
155      series.BorderDashStyle = ChartDashStyle.Solid;
156      series.BorderColor = Color.Empty;
157
158      if (row.VisualProperties.Color != Color.Empty)
159        series.Color = row.VisualProperties.Color;
160      else series.Color = Color.Empty;
161      series.IsVisibleInLegend = row.VisualProperties.IsVisibleInLegend;
162      series.ChartType = SeriesChartType.FastPoint;
163      series.MarkerSize = row.VisualProperties.PointSize;
164      series.MarkerStyle = ConvertPointStyle(row.VisualProperties.PointStyle);
165      series.XAxisType = AxisType.Primary;
166      series.YAxisType = AxisType.Primary;
167
168      if (row.VisualProperties.DisplayName.Trim() != String.Empty) series.LegendText = row.VisualProperties.DisplayName;
169      else series.LegendText = row.Name;
170
171      string xAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.XAxisTitle)
172                      ? "X"
173                      : Content.VisualProperties.XAxisTitle;
174      string yAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.YAxisTitle)
175                            ? "Y"
176                            : Content.VisualProperties.YAxisTitle;
177      series.ToolTip =
178        series.LegendText + Environment.NewLine +
179        xAxisTitle + " = " + "#VALX," + Environment.NewLine +
180        yAxisTitle + " = " + "#VAL";
181    }
182
183    private void ConfigureChartArea(ChartArea area) {
184      if (Content.VisualProperties.TitleFont != null) chart.Titles[0].Font = Content.VisualProperties.TitleFont;
185      if (!Content.VisualProperties.TitleColor.IsEmpty) chart.Titles[0].ForeColor = Content.VisualProperties.TitleColor;
186      chart.Titles[0].Text = Content.VisualProperties.Title;
187
188      if (Content.VisualProperties.AxisTitleFont != null) area.AxisX.TitleFont = Content.VisualProperties.AxisTitleFont;
189      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisX.TitleForeColor = Content.VisualProperties.AxisTitleColor;
190      area.AxisX.Title = Content.VisualProperties.XAxisTitle;
191      area.AxisX.MajorGrid.Enabled = Content.VisualProperties.XAxisGrid;
192
193      if (Content.VisualProperties.AxisTitleFont != null) area.AxisY.TitleFont = Content.VisualProperties.AxisTitleFont;
194      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisY.TitleForeColor = Content.VisualProperties.AxisTitleColor;
195      area.AxisY.Title = Content.VisualProperties.YAxisTitle;
196      area.AxisY.MajorGrid.Enabled = Content.VisualProperties.YAxisGrid;
197    }
198
199    private void RecalculateAxesScale(ChartArea area) {
200      area.AxisX.Minimum = CalculateMinBound(xMin);
201      area.AxisX.Maximum = CalculateMaxBound(xMax);
202      if (area.AxisX.Minimum == area.AxisX.Maximum) {
203        area.AxisX.Minimum = xMin - 0.5;
204        area.AxisX.Maximum = xMax + 0.5;
205      }
206      area.AxisY.Minimum = CalculateMinBound(yMin);
207      area.AxisY.Maximum = CalculateMaxBound(yMax);
208      if (area.AxisY.Minimum == area.AxisY.Maximum) {
209        area.AxisY.Minimum = yMin - 0.5;
210        area.AxisY.Maximum = yMax + 0.5;
211      }
212      if (xMax - xMin > 0) area.CursorX.Interval = Math.Pow(10, Math.Floor(Math.Log10(area.AxisX.Maximum - area.AxisX.Minimum) - 3));
213      else area.CursorX.Interval = 1;
214      area.AxisX.IsMarginVisible = false;
215
216      if (!Content.VisualProperties.XAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.XAxisMinimumFixedValue)) area.AxisX.Minimum = Content.VisualProperties.XAxisMinimumFixedValue;
217      if (!Content.VisualProperties.XAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.XAxisMaximumFixedValue)) area.AxisX.Maximum = Content.VisualProperties.XAxisMaximumFixedValue;
218      if (!Content.VisualProperties.YAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.YAxisMinimumFixedValue)) area.AxisY.Minimum = Content.VisualProperties.YAxisMinimumFixedValue;
219      if (!Content.VisualProperties.YAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.YAxisMaximumFixedValue)) area.AxisY.Maximum = Content.VisualProperties.YAxisMaximumFixedValue;
220    }
221
222    private static double CalculateMinBound(double min) {
223      if (min == 0) return 0;
224      var scale = Math.Pow(10, Math.Floor(Math.Log10(Math.Abs(min))));
225      return scale * (Math.Floor(min / scale));
226    }
227
228    private static double CalculateMaxBound(double max) {
229      if (max == 0) return 0;
230      var scale = Math.Pow(10, Math.Floor(Math.Log10(Math.Abs(max))));
231      return scale * (Math.Ceiling(max / scale));
232    }
233
234    protected virtual void UpdateYCursorInterval() {
235      double interestingValuesRange = (
236        from series in chart.Series
237        where series.Enabled
238        let values = (from point in series.Points
239                      where !point.IsEmpty
240                      select point.YValues[0]).DefaultIfEmpty(1.0)
241        let range = values.Max() - values.Min()
242        where range > 0.0
243        select range
244        ).DefaultIfEmpty(1.0).Min();
245
246      double digits = (int)Math.Log10(interestingValuesRange) - 3;
247      double yZoomInterval = Math.Pow(10, digits);
248      this.chart.ChartAreas[0].CursorY.Interval = yZoomInterval;
249    }
250
251    #region Event Handlers
252    #region Content Event Handlers
253    protected override void Content_NameChanged(object sender, EventArgs e) {
254      if (InvokeRequired)
255        Invoke(new EventHandler(Content_NameChanged), sender, e);
256      else {
257        chart.Titles[0].Text = Content.Name;
258        base.Content_NameChanged(sender, e);
259      }
260    }
261    private void Content_VisualPropertiesChanged(object sender, EventArgs e) {
262      if (InvokeRequired)
263        Invoke(new EventHandler(Content_VisualPropertiesChanged), sender, e);
264      else {
265        ConfigureChartArea(chart.ChartAreas[0]);
266        RecalculateAxesScale(chart.ChartAreas[0]); // axes min/max could have changed
267      }
268    }
269    #endregion
270    #region Rows Event Handlers
271    private void Rows_ItemsAdded(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
272      if (InvokeRequired)
273        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsAdded), sender, e);
274      else {
275        AddScatterPlotDataRows(e.Items);
276      }
277    }
278    private void Rows_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
279      if (InvokeRequired)
280        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsRemoved), sender, e);
281      else {
282        RemoveScatterPlotDataRows(e.Items);
283      }
284    }
285    private void Rows_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
286      if (InvokeRequired)
287        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsReplaced), sender, e);
288      else {
289        RemoveScatterPlotDataRows(e.OldItems);
290        AddScatterPlotDataRows(e.Items);
291      }
292    }
293    private void Rows_CollectionReset(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
294      if (InvokeRequired)
295        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_CollectionReset), sender, e);
296      else {
297        RemoveScatterPlotDataRows(e.OldItems);
298        AddScatterPlotDataRows(e.Items);
299      }
300    }
301    #endregion
302    #region Row Event Handlers
303    private void Row_VisualPropertiesChanged(object sender, EventArgs e) {
304      if (InvokeRequired)
305        Invoke(new EventHandler(Row_VisualPropertiesChanged), sender, e);
306      else {
307        ScatterPlotDataRow row = (ScatterPlotDataRow)sender;
308        Series series = chart.Series[row.Name];
309        series.Points.Clear();
310        ConfigureSeries(series, row);
311        FillSeriesWithRowValues(series, row);
312        RecalculateMinMaxPointValues();
313        RecalculateAxesScale(chart.ChartAreas[0]);
314      }
315    }
316    private void Row_NameChanged(object sender, EventArgs e) {
317      if (InvokeRequired)
318        Invoke(new EventHandler(Row_NameChanged), sender, e);
319      else {
320        ScatterPlotDataRow row = (ScatterPlotDataRow)sender;
321        chart.Series[row.Name].Name = row.Name;
322      }
323    }
324    #endregion
325    #region Points Event Handlers
326    private void Points_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
327      if (InvokeRequired)
328        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsAdded), sender, e);
329      else {
330        ScatterPlotDataRow row = null;
331        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
332        if (row != null) {
333          Series rowSeries = chart.Series[row.Name];
334          if (!invisibleSeries.Contains(rowSeries)) {
335            rowSeries.Points.Clear();
336            FillSeriesWithRowValues(rowSeries, row);
337            RecalculateMinMaxPointValues();
338            RecalculateAxesScale(chart.ChartAreas[0]);
339            UpdateYCursorInterval();
340          }
341        }
342      }
343    }
344    private void Points_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
345      if (InvokeRequired)
346        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsRemoved), sender, e);
347      else {
348        ScatterPlotDataRow row = null;
349        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
350        if (row != null) {
351          Series rowSeries = chart.Series[row.Name];
352          if (!invisibleSeries.Contains(rowSeries)) {
353            rowSeries.Points.Clear();
354            FillSeriesWithRowValues(rowSeries, row);
355            RecalculateMinMaxPointValues();
356            RecalculateAxesScale(chart.ChartAreas[0]);
357            UpdateYCursorInterval();
358          }
359        }
360      }
361    }
362    private void Points_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
363      if (InvokeRequired)
364        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsReplaced), sender, e);
365      else {
366        ScatterPlotDataRow row = null;
367        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
368        if (row != null) {
369          Series rowSeries = chart.Series[row.Name];
370          if (!invisibleSeries.Contains(rowSeries)) {
371            rowSeries.Points.Clear();
372            FillSeriesWithRowValues(rowSeries, row);
373            RecalculateMinMaxPointValues();
374            RecalculateAxesScale(chart.ChartAreas[0]);
375            UpdateYCursorInterval();
376          }
377        }
378      }
379    }
380    private void Points_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
381      if (InvokeRequired)
382        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_CollectionReset), sender, e);
383      else {
384        ScatterPlotDataRow row = null;
385        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
386        if (row != null) {
387          Series rowSeries = chart.Series[row.Name];
388          if (!invisibleSeries.Contains(rowSeries)) {
389            rowSeries.Points.Clear();
390            FillSeriesWithRowValues(rowSeries, row);
391            RecalculateMinMaxPointValues();
392            RecalculateAxesScale(chart.ChartAreas[0]);
393            UpdateYCursorInterval();
394          }
395        }
396      }
397    }
398    #endregion
399    #endregion
400
401    #region Chart Event Handlers
402    private void chart_MouseDown(object sender, MouseEventArgs e) {
403      HitTestResult result = chart.HitTest(e.X, e.Y);
404      if (result.ChartElementType == ChartElementType.LegendItem) {
405        ToggleSeriesVisible(result.Series);
406      }
407    }
408    private void chart_MouseMove(object sender, MouseEventArgs e) {
409      HitTestResult result = chart.HitTest(e.X, e.Y);
410      if (result.ChartElementType == ChartElementType.LegendItem)
411        this.Cursor = Cursors.Hand;
412      else
413        this.Cursor = Cursors.Default;
414    }
415    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
416      foreach (LegendItem legendItem in e.LegendItems) {
417        var series = chart.Series[legendItem.SeriesName];
418        if (series != null) {
419          bool seriesIsInvisible = invisibleSeries.Contains(series);
420          foreach (LegendCell cell in legendItem.Cells) {
421            cell.ForeColor = seriesIsInvisible ? Color.Gray : Color.Black;
422          }
423        }
424      }
425    }
426    #endregion
427
428    private void ToggleSeriesVisible(Series series) {
429      if (!invisibleSeries.Contains(series)) {
430        series.Points.Clear();
431        invisibleSeries.Add(series);
432        RecalculateMinMaxPointValues();
433      } else {
434        invisibleSeries.Remove(series);
435        if (Content != null) {
436
437          var row = (from r in Content.Rows
438                     where r.Name == series.Name
439                     select r).Single();
440          FillSeriesWithRowValues(series, row);
441          RecalculateMinMaxPointValues();
442          this.chart.Legends[series.Legend].ForeColor = Color.Black;
443          RecalculateAxesScale(chart.ChartAreas[0]);
444          UpdateYCursorInterval();
445        }
446      }
447    }
448
449    private void RecalculateMinMaxPointValues() {
450      yMin = xMin = double.MaxValue;
451      yMax = xMax = double.MinValue;
452      foreach (var s in chart.Series.Where(x => x.Enabled)) {
453        foreach (var p in s.Points) {
454          double x = p.XValue, y = p.YValues[0];
455          if (xMin > x) xMin = x;
456          if (xMax < x) xMax = x;
457          if (yMin > y) yMin = y;
458          if (yMax < y) yMax = y;
459        }
460      }
461    }
462
463    private void FillSeriesWithRowValues(Series series, ScatterPlotDataRow row) {
464      if (row.VisualProperties.ShowRegressionLine) {
465        var xs = row.Points.Select(p => p.X).ToArray();
466        var xsMin = xs.Min();
467        var xsMax = xs.Max();
468        var ys = row.Points.Select(p => p.Y).ToArray();
469        var corr = alglib.pearsoncorr2(xs, ys);
470        var slope = corr * ys.StandardDeviation() / xs.StandardDeviation();
471        if (!double.IsNaN(slope) && !double.IsInfinity(slope)) {
472          var off = ys.Average() - slope * xs.Average();
473
474          Series lrSeries;
475          if (chart.Series.IsUniqueName(series.Name + ".lr")) {
476            lrSeries = new Series(series.Name + ".lr") {IsVisibleInLegend = false, ChartType = SeriesChartType.FastLine};
477            chart.Series.Add(lrSeries);
478          } else lrSeries = chart.Series[series.Name + ".lr"];
479          lrSeries.Points.Clear();
480          lrSeries.Points.AddXY(xsMin, slope * xsMin + off);
481          lrSeries.Points.AddXY(xsMax, slope * xsMax + off);
482        }
483      } else if (!chart.Series.IsUniqueName(series.Name + ".lr"))
484        chart.Series.Remove(chart.Series[series.Name + ".lr"]);
485
486      for (int i = 0; i < row.Points.Count; i++) {
487        var value = row.Points[i];
488        DataPoint point = new DataPoint();
489        if (IsInvalidValue(value.X) || IsInvalidValue(value.Y))
490          point.IsEmpty = true;
491        else {
492          point.XValue = value.X;
493          point.YValues = new double[] { value.Y };
494        }
495        series.Points.Add(point);
496      }
497    }
498
499    #region Helpers
500    private MarkerStyle ConvertPointStyle(ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle pointStyle) {
501      switch (pointStyle) {
502        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Circle:
503          return MarkerStyle.Circle;
504        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Cross:
505          return MarkerStyle.Cross;
506        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Diamond:
507          return MarkerStyle.Diamond;
508        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Square:
509          return MarkerStyle.Square;
510        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star4:
511          return MarkerStyle.Star4;
512        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star5:
513          return MarkerStyle.Star5;
514        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star6:
515          return MarkerStyle.Star6;
516        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star10:
517          return MarkerStyle.Star10;
518        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Triangle:
519          return MarkerStyle.Triangle;
520        default:
521          return MarkerStyle.None;
522      }
523    }
524
525    protected static bool IsInvalidValue(double x) {
526      return double.IsNaN(x) || x < (double)decimal.MinValue || x > (double)decimal.MaxValue;
527    }
528    #endregion
529  }
530}
Note: See TracBrowser for help on using the repository browser.