Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Analysis.Views/3.3/ScatterPlotView.cs @ 12614

Last change on this file since 12614 was 12614, checked in by abeham, 9 years ago

#2274: Fixed bug in cluster visualization view and added nicer bounds in scatter plot

File size: 23.0 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 System;
23using System.Collections.Generic;
24using System.Drawing;
25using System.Linq;
26using System.Windows.Forms;
27using System.Windows.Forms.DataVisualization.Charting;
28using HeuristicLab.Collections;
29using HeuristicLab.Common;
30using HeuristicLab.Core.Views;
31using HeuristicLab.MainForm;
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        chart.Series.Remove(series);
144        if (invisibleSeries.Contains(series))
145          invisibleSeries.Remove(series);
146      }
147      RecalculateMinMaxPointValues();
148      RecalculateAxesScale(chart.ChartAreas[0]);
149    }
150
151    private void ConfigureSeries(Series series, ScatterPlotDataRow row) {
152      series.BorderWidth = 1;
153      series.BorderDashStyle = ChartDashStyle.Solid;
154      series.BorderColor = Color.Empty;
155
156      if (row.VisualProperties.Color != Color.Empty)
157        series.Color = row.VisualProperties.Color;
158      else series.Color = Color.Empty;
159      series.IsVisibleInLegend = row.VisualProperties.IsVisibleInLegend;
160      series.ChartType = SeriesChartType.FastPoint;
161      series.MarkerSize = row.VisualProperties.PointSize;
162      series.MarkerStyle = ConvertPointStyle(row.VisualProperties.PointStyle);
163      series.XAxisType = AxisType.Primary;
164      series.YAxisType = AxisType.Primary;
165
166      if (row.VisualProperties.DisplayName.Trim() != String.Empty) series.LegendText = row.VisualProperties.DisplayName;
167      else series.LegendText = row.Name;
168
169      string xAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.XAxisTitle)
170                      ? "X"
171                      : Content.VisualProperties.XAxisTitle;
172      string yAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.YAxisTitle)
173                            ? "Y"
174                            : Content.VisualProperties.YAxisTitle;
175      series.ToolTip =
176        series.LegendText + Environment.NewLine +
177        xAxisTitle + " = " + "#VALX," + Environment.NewLine +
178        yAxisTitle + " = " + "#VAL";
179    }
180
181    private void ConfigureChartArea(ChartArea area) {
182      if (Content.VisualProperties.TitleFont != null) chart.Titles[0].Font = Content.VisualProperties.TitleFont;
183      if (!Content.VisualProperties.TitleColor.IsEmpty) chart.Titles[0].ForeColor = Content.VisualProperties.TitleColor;
184      chart.Titles[0].Text = Content.VisualProperties.Title;
185
186      if (Content.VisualProperties.AxisTitleFont != null) area.AxisX.TitleFont = Content.VisualProperties.AxisTitleFont;
187      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisX.TitleForeColor = Content.VisualProperties.AxisTitleColor;
188      area.AxisX.Title = Content.VisualProperties.XAxisTitle;
189      area.AxisX.MajorGrid.Enabled = Content.VisualProperties.XAxisGrid;
190
191      if (Content.VisualProperties.AxisTitleFont != null) area.AxisY.TitleFont = Content.VisualProperties.AxisTitleFont;
192      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisY.TitleForeColor = Content.VisualProperties.AxisTitleColor;
193      area.AxisY.Title = Content.VisualProperties.YAxisTitle;
194      area.AxisY.MajorGrid.Enabled = Content.VisualProperties.YAxisGrid;
195    }
196
197    private void RecalculateAxesScale(ChartArea area) {
198      // Reset the axes bounds so that RecalculateAxesScale() will assign new bounds
199      area.AxisX.Minimum = CalculateMinBound(xMin);
200      area.AxisX.Maximum = CalculateMaxBound(xMax);
201      area.AxisY.Minimum = CalculateMinBound(yMin);
202      area.AxisY.Maximum = CalculateMaxBound(yMax);
203      area.AxisX.IsMarginVisible = false;
204
205      if (!Content.VisualProperties.XAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.XAxisMinimumFixedValue)) area.AxisX.Minimum = Content.VisualProperties.XAxisMinimumFixedValue;
206      if (!Content.VisualProperties.XAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.XAxisMaximumFixedValue)) area.AxisX.Maximum = Content.VisualProperties.XAxisMaximumFixedValue;
207      if (!Content.VisualProperties.YAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.YAxisMinimumFixedValue)) area.AxisY.Minimum = Content.VisualProperties.YAxisMinimumFixedValue;
208      if (!Content.VisualProperties.YAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.YAxisMaximumFixedValue)) area.AxisY.Maximum = Content.VisualProperties.YAxisMaximumFixedValue;
209    }
210
211    private static double CalculateMinBound(double min) {
212      double newMin;
213      if (min < 0) {
214        newMin = -Math.Pow(10, Math.Ceiling(Math.Log10(Math.Abs(min))));
215        if (newMin / 1.25 < min) newMin /= 1.25;
216        if (newMin / 1.6 < min) newMin /= 1.6;
217        if (newMin / 2.5 < min) newMin /= 2.5;
218        if (newMin / 2.0 < min) newMin /= 2.0;
219      } else {
220        newMin = Math.Pow(10, Math.Floor(Math.Log10(min)));
221        if (newMin * 1.25 < min) newMin *= 1.25;
222        if (newMin * 1.6 < min) newMin *= 1.6;
223        if (newMin * 2.5 < min) newMin *= 2.5;
224        if (newMin * 2.0 < min) newMin *= 2.0;
225      }
226      return newMin;
227    }
228
229    private static double CalculateMaxBound(double max) {
230      double newMax;
231      if (max < 0) {
232        newMax = -Math.Pow(10, Math.Floor(Math.Log10(Math.Abs(max))));
233        if (newMax * 1.25 > max) newMax *= 1.25;
234        if (newMax * 1.6 > max) newMax *= 1.6;
235        if (newMax * 2.5 > max) newMax *= 2.5;
236        if (newMax * 2.0 > max) newMax *= 2.0;
237      } else {
238        newMax = Math.Pow(10, Math.Ceiling(Math.Log10(max)));
239        if (newMax / 1.25 > max) newMax /= 1.25;
240        if (newMax / 1.6 > max) newMax /= 1.6;
241        if (newMax / 2.5 > max) newMax /= 2.5;
242        if (newMax / 2.0 > max) newMax /= 2.0;
243      }
244      return newMax;
245    }
246
247    protected virtual void UpdateYCursorInterval() {
248      double interestingValuesRange = (
249        from series in chart.Series
250        where series.Enabled
251        let values = (from point in series.Points
252                      where !point.IsEmpty
253                      select point.YValues[0]).DefaultIfEmpty(1.0)
254        let range = values.Max() - values.Min()
255        where range > 0.0
256        select range
257        ).DefaultIfEmpty(1.0).Min();
258
259      double digits = (int)Math.Log10(interestingValuesRange) - 3;
260      double yZoomInterval = Math.Pow(10, digits);
261      this.chart.ChartAreas[0].CursorY.Interval = yZoomInterval;
262    }
263
264    #region Event Handlers
265    #region Content Event Handlers
266    protected override void Content_NameChanged(object sender, EventArgs e) {
267      if (InvokeRequired)
268        Invoke(new EventHandler(Content_NameChanged), sender, e);
269      else {
270        chart.Titles[0].Text = Content.Name;
271        base.Content_NameChanged(sender, e);
272      }
273    }
274    private void Content_VisualPropertiesChanged(object sender, EventArgs e) {
275      if (InvokeRequired)
276        Invoke(new EventHandler(Content_VisualPropertiesChanged), sender, e);
277      else {
278        ConfigureChartArea(chart.ChartAreas[0]);
279        RecalculateAxesScale(chart.ChartAreas[0]); // axes min/max could have changed
280      }
281    }
282    #endregion
283    #region Rows Event Handlers
284    private void Rows_ItemsAdded(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
285      if (InvokeRequired)
286        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsAdded), sender, e);
287      else {
288        AddScatterPlotDataRows(e.Items);
289      }
290    }
291    private void Rows_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
292      if (InvokeRequired)
293        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsRemoved), sender, e);
294      else {
295        RemoveScatterPlotDataRows(e.Items);
296      }
297    }
298    private void Rows_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
299      if (InvokeRequired)
300        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsReplaced), sender, e);
301      else {
302        RemoveScatterPlotDataRows(e.OldItems);
303        AddScatterPlotDataRows(e.Items);
304      }
305    }
306    private void Rows_CollectionReset(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
307      if (InvokeRequired)
308        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_CollectionReset), sender, e);
309      else {
310        RemoveScatterPlotDataRows(e.OldItems);
311        AddScatterPlotDataRows(e.Items);
312      }
313    }
314    #endregion
315    #region Row Event Handlers
316    private void Row_VisualPropertiesChanged(object sender, EventArgs e) {
317      if (InvokeRequired)
318        Invoke(new EventHandler(Row_VisualPropertiesChanged), sender, e);
319      else {
320        ScatterPlotDataRow row = (ScatterPlotDataRow)sender;
321        Series series = chart.Series[row.Name];
322        series.Points.Clear();
323        ConfigureSeries(series, row);
324        FillSeriesWithRowValues(series, row);
325        RecalculateMinMaxPointValues();
326        RecalculateAxesScale(chart.ChartAreas[0]);
327      }
328    }
329    private void Row_NameChanged(object sender, EventArgs e) {
330      if (InvokeRequired)
331        Invoke(new EventHandler(Row_NameChanged), sender, e);
332      else {
333        ScatterPlotDataRow row = (ScatterPlotDataRow)sender;
334        chart.Series[row.Name].Name = row.Name;
335      }
336    }
337    #endregion
338    #region Points Event Handlers
339    private void Points_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
340      if (InvokeRequired)
341        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsAdded), sender, e);
342      else {
343        ScatterPlotDataRow row = null;
344        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
345        if (row != null) {
346          Series rowSeries = chart.Series[row.Name];
347          if (!invisibleSeries.Contains(rowSeries)) {
348            rowSeries.Points.Clear();
349            FillSeriesWithRowValues(rowSeries, row);
350            RecalculateMinMaxPointValues();
351            RecalculateAxesScale(chart.ChartAreas[0]);
352            UpdateYCursorInterval();
353          }
354        }
355      }
356    }
357    private void Points_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
358      if (InvokeRequired)
359        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsRemoved), sender, e);
360      else {
361        ScatterPlotDataRow row = null;
362        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
363        if (row != null) {
364          Series rowSeries = chart.Series[row.Name];
365          if (!invisibleSeries.Contains(rowSeries)) {
366            rowSeries.Points.Clear();
367            FillSeriesWithRowValues(rowSeries, row);
368            RecalculateMinMaxPointValues();
369            RecalculateAxesScale(chart.ChartAreas[0]);
370            UpdateYCursorInterval();
371          }
372        }
373      }
374    }
375    private void Points_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
376      if (InvokeRequired)
377        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsReplaced), sender, e);
378      else {
379        ScatterPlotDataRow row = null;
380        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
381        if (row != null) {
382          Series rowSeries = chart.Series[row.Name];
383          if (!invisibleSeries.Contains(rowSeries)) {
384            rowSeries.Points.Clear();
385            FillSeriesWithRowValues(rowSeries, row);
386            RecalculateMinMaxPointValues();
387            RecalculateAxesScale(chart.ChartAreas[0]);
388            UpdateYCursorInterval();
389          }
390        }
391      }
392    }
393    private void Points_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
394      if (InvokeRequired)
395        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_CollectionReset), sender, e);
396      else {
397        ScatterPlotDataRow row = null;
398        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
399        if (row != null) {
400          Series rowSeries = chart.Series[row.Name];
401          if (!invisibleSeries.Contains(rowSeries)) {
402            rowSeries.Points.Clear();
403            FillSeriesWithRowValues(rowSeries, row);
404            RecalculateMinMaxPointValues();
405            RecalculateAxesScale(chart.ChartAreas[0]);
406            UpdateYCursorInterval();
407          }
408        }
409      }
410    }
411    #endregion
412    #endregion
413
414    #region Chart Event Handlers
415    private void chart_MouseDown(object sender, MouseEventArgs e) {
416      HitTestResult result = chart.HitTest(e.X, e.Y);
417      if (result.ChartElementType == ChartElementType.LegendItem) {
418        ToggleSeriesVisible(result.Series);
419      }
420    }
421    private void chart_MouseMove(object sender, MouseEventArgs e) {
422      HitTestResult result = chart.HitTest(e.X, e.Y);
423      if (result.ChartElementType == ChartElementType.LegendItem)
424        this.Cursor = Cursors.Hand;
425      else
426        this.Cursor = Cursors.Default;
427    }
428    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
429      foreach (LegendItem legendItem in e.LegendItems) {
430        var series = chart.Series[legendItem.SeriesName];
431        if (series != null) {
432          bool seriesIsInvisible = invisibleSeries.Contains(series);
433          foreach (LegendCell cell in legendItem.Cells) {
434            cell.ForeColor = seriesIsInvisible ? Color.Gray : Color.Black;
435          }
436        }
437      }
438    }
439    #endregion
440
441    private void ToggleSeriesVisible(Series series) {
442      if (!invisibleSeries.Contains(series)) {
443        series.Points.Clear();
444        invisibleSeries.Add(series);
445        RecalculateMinMaxPointValues();
446      } else {
447        invisibleSeries.Remove(series);
448        if (Content != null) {
449
450          var row = (from r in Content.Rows
451                     where r.Name == series.Name
452                     select r).Single();
453          FillSeriesWithRowValues(series, row);
454          RecalculateMinMaxPointValues();
455          this.chart.Legends[series.Legend].ForeColor = Color.Black;
456          RecalculateAxesScale(chart.ChartAreas[0]);
457          UpdateYCursorInterval();
458        }
459      }
460    }
461
462    private void RecalculateMinMaxPointValues() {
463      yMin = xMin = double.MaxValue;
464      yMax = xMax = double.MinValue;
465      foreach (var s in chart.Series.Where(x => x.Enabled)) {
466        foreach (var p in s.Points) {
467          double x = p.XValue, y = p.YValues[0];
468          if (xMin > x) xMin = x;
469          if (xMax < x) xMax = x;
470          if (yMin > y) yMin = y;
471          if (yMax < y) yMax = y;
472        }
473      }
474    }
475
476    private void FillSeriesWithRowValues(Series series, ScatterPlotDataRow row) {
477      for (int i = 0; i < row.Points.Count; i++) {
478        var value = row.Points[i];
479        DataPoint point = new DataPoint();
480        if (IsInvalidValue(value.X) || IsInvalidValue(value.Y))
481          point.IsEmpty = true;
482        else {
483          point.XValue = value.X;
484          point.YValues = new double[] { value.Y };
485        }
486        series.Points.Add(point);
487      }
488    }
489
490    #region Helpers
491    private MarkerStyle ConvertPointStyle(ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle pointStyle) {
492      switch (pointStyle) {
493        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Circle:
494          return MarkerStyle.Circle;
495        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Cross:
496          return MarkerStyle.Cross;
497        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Diamond:
498          return MarkerStyle.Diamond;
499        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Square:
500          return MarkerStyle.Square;
501        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star4:
502          return MarkerStyle.Star4;
503        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star5:
504          return MarkerStyle.Star5;
505        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star6:
506          return MarkerStyle.Star6;
507        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star10:
508          return MarkerStyle.Star10;
509        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Triangle:
510          return MarkerStyle.Triangle;
511        default:
512          return MarkerStyle.None;
513      }
514    }
515
516    protected static bool IsInvalidValue(double x) {
517      return double.IsNaN(x) || x < (double)decimal.MinValue || x > (double)decimal.MaxValue;
518    }
519    #endregion
520  }
521}
Note: See TracBrowser for help on using the repository browser.