Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Analysis.Views/3.3/ScatterPlotControl.cs @ 14469

Last change on this file since 14469 was 14439, checked in by pfleck, 8 years ago

#2713 Moved the charting logic out of DataTableView and ScatterPlotView into new DataTableControl and ScatterPlotControl.
This way, the charts can be reused without the name-textbox and description from the NamedItemView.

File size: 22.5 KB
RevLine 
[8280]1#region License Information
[7829]2/* HeuristicLab
[14185]3 * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[7829]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;
[8280]23using System.Collections.Generic;
[7829]24using System.Drawing;
[8280]25using System.Linq;
[7829]26using System.Windows.Forms;
[8280]27using System.Windows.Forms.DataVisualization.Charting;
[7829]28using HeuristicLab.Collections;
[8280]29using HeuristicLab.Common;
[7829]30
31namespace HeuristicLab.Analysis.Views {
[14439]32  public partial class ScatterPlotControl : UserControl {
[8280]33    protected List<Series> invisibleSeries;
34    protected Dictionary<IObservableList<Point2D<double>>, ScatterPlotDataRow> pointsRowsTable;
[12614]35    private double xMin, xMax, yMin, yMax;
[8280]36
[14439]37    private ScatterPlot content;
38    public ScatterPlot Content {
39      get { return content; }
40      set {
41        if (value == content) return;
42        if (content != null) DeregisterContentEvents();
43        content = value;
44        if (content != null) RegisterContentEvents();
45        OnContentChanged();
46        SetEnabledStateOfControls();
47      }
[7829]48    }
49
[14439]50    public ScatterPlotControl() {
[7829]51      InitializeComponent();
[8280]52      pointsRowsTable = new Dictionary<IObservableList<Point2D<double>>, ScatterPlotDataRow>();
53      invisibleSeries = new List<Series>();
[7829]54      chart.CustomizeAllChartAreas();
[8280]55      chart.ChartAreas[0].CursorX.Interval = 1;
[14435]56      chart.ContextMenuStrip.Items.Add(configureToolStripMenuItem);
[7829]57    }
58
[8280]59    #region Event Handler Registration
[14439]60    protected virtual void DeregisterContentEvents() {
[8280]61      foreach (ScatterPlotDataRow row in Content.Rows)
62        DeregisterScatterPlotDataRowEvents(row);
63      Content.VisualPropertiesChanged -= new EventHandler(Content_VisualPropertiesChanged);
64      Content.Rows.ItemsAdded -= new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsAdded);
65      Content.Rows.ItemsRemoved -= new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsRemoved);
66      Content.Rows.ItemsReplaced -= new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsReplaced);
67      Content.Rows.CollectionReset -= new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_CollectionReset);
[7829]68    }
[14439]69    protected virtual void RegisterContentEvents() {
[8280]70      Content.VisualPropertiesChanged += new EventHandler(Content_VisualPropertiesChanged);
71      Content.Rows.ItemsAdded += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsAdded);
72      Content.Rows.ItemsRemoved += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsRemoved);
73      Content.Rows.ItemsReplaced += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsReplaced);
74      Content.Rows.CollectionReset += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_CollectionReset);
[7829]75    }
76
[8280]77    protected virtual void RegisterScatterPlotDataRowEvents(ScatterPlotDataRow row) {
78      row.NameChanged += new EventHandler(Row_NameChanged);
79      row.VisualPropertiesChanged += new EventHandler(Row_VisualPropertiesChanged);
80      pointsRowsTable.Add(row.Points, row);
81      row.Points.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsAdded);
82      row.Points.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsRemoved);
83      row.Points.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsReplaced);
84      row.Points.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_CollectionReset);
[7829]85    }
[8280]86    protected virtual void DeregisterScatterPlotDataRowEvents(ScatterPlotDataRow row) {
87      row.Points.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsAdded);
88      row.Points.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsRemoved);
89      row.Points.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsReplaced);
90      row.Points.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_CollectionReset);
91      pointsRowsTable.Remove(row.Points);
92      row.VisualPropertiesChanged -= new EventHandler(Row_VisualPropertiesChanged);
93      row.NameChanged -= new EventHandler(Row_NameChanged);
94    }
95    #endregion
[7829]96
[14439]97    protected virtual void OnContentChanged() {
[8280]98      invisibleSeries.Clear();
99      chart.Titles[0].Text = string.Empty;
100      chart.ChartAreas[0].AxisX.Title = string.Empty;
101      chart.ChartAreas[0].AxisY.Title = string.Empty;
102      chart.Series.Clear();
[7829]103      if (Content != null) {
[8280]104        chart.Titles[0].Text = Content.Name;
[14438]105        chart.Titles[0].Visible = !string.IsNullOrEmpty(Content.Name);
[8280]106        AddScatterPlotDataRows(Content.Rows);
107        ConfigureChartArea(chart.ChartAreas[0]);
[12614]108        RecalculateMinMaxPointValues();
[8280]109        RecalculateAxesScale(chart.ChartAreas[0]);
[7829]110      }
111    }
112
[14439]113    protected virtual void SetEnabledStateOfControls() {
[8280]114      chart.Enabled = Content != null;
[7829]115    }
116
[8907]117    public void ShowConfiguration() {
118      if (Content != null) {
119        using (ScatterPlotVisualPropertiesDialog dialog = new ScatterPlotVisualPropertiesDialog(Content)) {
120          dialog.ShowDialog(this);
121        }
122      } else MessageBox.Show("Nothing to configure.");
123    }
124
[8280]125    protected virtual void AddScatterPlotDataRows(IEnumerable<ScatterPlotDataRow> rows) {
126      foreach (var row in rows) {
127        RegisterScatterPlotDataRowEvents(row);
128        Series series = new Series(row.Name);
129        if (row.VisualProperties.DisplayName.Trim() != String.Empty) series.LegendText = row.VisualProperties.DisplayName;
130        else series.LegendText = row.Name;
131        ConfigureSeries(series, row);
132        FillSeriesWithRowValues(series, row);
133        chart.Series.Add(series);
134      }
135      ConfigureChartArea(chart.ChartAreas[0]);
[12614]136      RecalculateMinMaxPointValues();
[8280]137      RecalculateAxesScale(chart.ChartAreas[0]);
138      UpdateYCursorInterval();
139    }
140
141    protected virtual void RemoveScatterPlotDataRows(IEnumerable<ScatterPlotDataRow> rows) {
142      foreach (var row in rows) {
143        DeregisterScatterPlotDataRowEvents(row);
144        Series series = chart.Series[row.Name];
145        chart.Series.Remove(series);
146        if (invisibleSeries.Contains(series))
147          invisibleSeries.Remove(series);
148      }
[12614]149      RecalculateMinMaxPointValues();
[8280]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;
[14438]187      chart.Titles[0].Visible = !string.IsNullOrEmpty(Content.VisualProperties.Title);
[8280]188
189      if (Content.VisualProperties.AxisTitleFont != null) area.AxisX.TitleFont = Content.VisualProperties.AxisTitleFont;
190      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisX.TitleForeColor = Content.VisualProperties.AxisTitleColor;
191      area.AxisX.Title = Content.VisualProperties.XAxisTitle;
[8282]192      area.AxisX.MajorGrid.Enabled = Content.VisualProperties.XAxisGrid;
[8280]193
194      if (Content.VisualProperties.AxisTitleFont != null) area.AxisY.TitleFont = Content.VisualProperties.AxisTitleFont;
195      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisY.TitleForeColor = Content.VisualProperties.AxisTitleColor;
196      area.AxisY.Title = Content.VisualProperties.YAxisTitle;
[8282]197      area.AxisY.MajorGrid.Enabled = Content.VisualProperties.YAxisGrid;
[8280]198    }
199
200    private void RecalculateAxesScale(ChartArea area) {
[12614]201      area.AxisX.Minimum = CalculateMinBound(xMin);
202      area.AxisX.Maximum = CalculateMaxBound(xMax);
[12670]203      if (area.AxisX.Minimum == area.AxisX.Maximum) {
204        area.AxisX.Minimum = xMin - 0.5;
205        area.AxisX.Maximum = xMax + 0.5;
206      }
[12614]207      area.AxisY.Minimum = CalculateMinBound(yMin);
208      area.AxisY.Maximum = CalculateMaxBound(yMax);
[12670]209      if (area.AxisY.Minimum == area.AxisY.Maximum) {
210        area.AxisY.Minimum = yMin - 0.5;
211        area.AxisY.Maximum = yMax + 0.5;
212      }
213      if (xMax - xMin > 0) area.CursorX.Interval = Math.Pow(10, Math.Floor(Math.Log10(area.AxisX.Maximum - area.AxisX.Minimum) - 3));
214      else area.CursorX.Interval = 1;
[8280]215      area.AxisX.IsMarginVisible = false;
216
217      if (!Content.VisualProperties.XAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.XAxisMinimumFixedValue)) area.AxisX.Minimum = Content.VisualProperties.XAxisMinimumFixedValue;
218      if (!Content.VisualProperties.XAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.XAxisMaximumFixedValue)) area.AxisX.Maximum = Content.VisualProperties.XAxisMaximumFixedValue;
219      if (!Content.VisualProperties.YAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.YAxisMinimumFixedValue)) area.AxisY.Minimum = Content.VisualProperties.YAxisMinimumFixedValue;
220      if (!Content.VisualProperties.YAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.YAxisMaximumFixedValue)) area.AxisY.Maximum = Content.VisualProperties.YAxisMaximumFixedValue;
221    }
222
[12614]223    private static double CalculateMinBound(double min) {
[12670]224      if (min == 0) return 0;
225      var scale = Math.Pow(10, Math.Floor(Math.Log10(Math.Abs(min))));
226      return scale * (Math.Floor(min / scale));
[12614]227    }
228
229    private static double CalculateMaxBound(double max) {
[12670]230      if (max == 0) return 0;
231      var scale = Math.Pow(10, Math.Floor(Math.Log10(Math.Abs(max))));
232      return scale * (Math.Ceiling(max / scale));
[12614]233    }
234
[8280]235    protected virtual void UpdateYCursorInterval() {
236      double interestingValuesRange = (
237        from series in chart.Series
238        where series.Enabled
239        let values = (from point in series.Points
240                      where !point.IsEmpty
241                      select point.YValues[0]).DefaultIfEmpty(1.0)
242        let range = values.Max() - values.Min()
243        where range > 0.0
244        select range
245        ).DefaultIfEmpty(1.0).Min();
246
247      double digits = (int)Math.Log10(interestingValuesRange) - 3;
248      double yZoomInterval = Math.Pow(10, digits);
249      this.chart.ChartAreas[0].CursorY.Interval = yZoomInterval;
250    }
251
252    #region Event Handlers
253    #region Content Event Handlers
254    private void Content_VisualPropertiesChanged(object sender, EventArgs e) {
255      if (InvokeRequired)
256        Invoke(new EventHandler(Content_VisualPropertiesChanged), sender, e);
257      else {
258        ConfigureChartArea(chart.ChartAreas[0]);
259        RecalculateAxesScale(chart.ChartAreas[0]); // axes min/max could have changed
260      }
261    }
262    #endregion
263    #region Rows Event Handlers
264    private void Rows_ItemsAdded(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
265      if (InvokeRequired)
266        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsAdded), sender, e);
267      else {
268        AddScatterPlotDataRows(e.Items);
269      }
270    }
271    private void Rows_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
272      if (InvokeRequired)
273        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsRemoved), sender, e);
274      else {
275        RemoveScatterPlotDataRows(e.Items);
276      }
277    }
278    private void Rows_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
279      if (InvokeRequired)
280        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsReplaced), sender, e);
281      else {
282        RemoveScatterPlotDataRows(e.OldItems);
283        AddScatterPlotDataRows(e.Items);
284      }
285    }
286    private void Rows_CollectionReset(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
287      if (InvokeRequired)
288        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_CollectionReset), sender, e);
289      else {
290        RemoveScatterPlotDataRows(e.OldItems);
291        AddScatterPlotDataRows(e.Items);
292      }
293    }
294    #endregion
295    #region Row Event Handlers
296    private void Row_VisualPropertiesChanged(object sender, EventArgs e) {
297      if (InvokeRequired)
298        Invoke(new EventHandler(Row_VisualPropertiesChanged), sender, e);
299      else {
300        ScatterPlotDataRow row = (ScatterPlotDataRow)sender;
301        Series series = chart.Series[row.Name];
302        series.Points.Clear();
303        ConfigureSeries(series, row);
304        FillSeriesWithRowValues(series, row);
[12614]305        RecalculateMinMaxPointValues();
[8280]306        RecalculateAxesScale(chart.ChartAreas[0]);
307      }
308    }
309    private void Row_NameChanged(object sender, EventArgs e) {
310      if (InvokeRequired)
311        Invoke(new EventHandler(Row_NameChanged), sender, e);
312      else {
313        ScatterPlotDataRow row = (ScatterPlotDataRow)sender;
314        chart.Series[row.Name].Name = row.Name;
315      }
316    }
317    #endregion
318    #region Points Event Handlers
319    private void Points_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
320      if (InvokeRequired)
321        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsAdded), sender, e);
322      else {
323        ScatterPlotDataRow row = null;
324        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
325        if (row != null) {
326          Series rowSeries = chart.Series[row.Name];
327          if (!invisibleSeries.Contains(rowSeries)) {
328            rowSeries.Points.Clear();
329            FillSeriesWithRowValues(rowSeries, row);
[12614]330            RecalculateMinMaxPointValues();
[8280]331            RecalculateAxesScale(chart.ChartAreas[0]);
332            UpdateYCursorInterval();
333          }
334        }
335      }
336    }
337    private void Points_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
338      if (InvokeRequired)
339        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsRemoved), sender, e);
340      else {
341        ScatterPlotDataRow row = null;
342        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
343        if (row != null) {
344          Series rowSeries = chart.Series[row.Name];
345          if (!invisibleSeries.Contains(rowSeries)) {
346            rowSeries.Points.Clear();
347            FillSeriesWithRowValues(rowSeries, row);
[12614]348            RecalculateMinMaxPointValues();
[8280]349            RecalculateAxesScale(chart.ChartAreas[0]);
350            UpdateYCursorInterval();
351          }
352        }
353      }
354    }
355    private void Points_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
356      if (InvokeRequired)
357        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsReplaced), sender, e);
358      else {
359        ScatterPlotDataRow row = null;
360        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
361        if (row != null) {
362          Series rowSeries = chart.Series[row.Name];
363          if (!invisibleSeries.Contains(rowSeries)) {
364            rowSeries.Points.Clear();
365            FillSeriesWithRowValues(rowSeries, row);
[12614]366            RecalculateMinMaxPointValues();
[8280]367            RecalculateAxesScale(chart.ChartAreas[0]);
368            UpdateYCursorInterval();
369          }
370        }
371      }
372    }
373    private void Points_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
374      if (InvokeRequired)
375        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_CollectionReset), sender, e);
376      else {
377        ScatterPlotDataRow row = null;
378        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
379        if (row != null) {
380          Series rowSeries = chart.Series[row.Name];
381          if (!invisibleSeries.Contains(rowSeries)) {
382            rowSeries.Points.Clear();
383            FillSeriesWithRowValues(rowSeries, row);
[12614]384            RecalculateMinMaxPointValues();
[8280]385            RecalculateAxesScale(chart.ChartAreas[0]);
386            UpdateYCursorInterval();
387          }
388        }
389      }
390    }
391    #endregion
[14435]392    private void configureToolStripMenuItem_Click(object sender, System.EventArgs e) {
393      ShowConfiguration();
394    }
[8280]395    #endregion
[7829]396
[8280]397    #region Chart Event Handlers
398    private void chart_MouseDown(object sender, MouseEventArgs e) {
399      HitTestResult result = chart.HitTest(e.X, e.Y);
400      if (result.ChartElementType == ChartElementType.LegendItem) {
401        ToggleSeriesVisible(result.Series);
[7829]402      }
403    }
[8280]404    private void chart_MouseMove(object sender, MouseEventArgs e) {
405      HitTestResult result = chart.HitTest(e.X, e.Y);
406      if (result.ChartElementType == ChartElementType.LegendItem)
407        this.Cursor = Cursors.Hand;
408      else
409        this.Cursor = Cursors.Default;
410    }
411    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
412      foreach (LegendItem legendItem in e.LegendItems) {
413        var series = chart.Series[legendItem.SeriesName];
414        if (series != null) {
415          bool seriesIsInvisible = invisibleSeries.Contains(series);
416          foreach (LegendCell cell in legendItem.Cells) {
417            cell.ForeColor = seriesIsInvisible ? Color.Gray : Color.Black;
418          }
419        }
420      }
421    }
422    #endregion
[7829]423
[8280]424    private void ToggleSeriesVisible(Series series) {
425      if (!invisibleSeries.Contains(series)) {
426        series.Points.Clear();
427        invisibleSeries.Add(series);
[12614]428        RecalculateMinMaxPointValues();
[7829]429      } else {
[8280]430        invisibleSeries.Remove(series);
431        if (Content != null) {
432
433          var row = (from r in Content.Rows
434                     where r.Name == series.Name
435                     select r).Single();
436          FillSeriesWithRowValues(series, row);
[12614]437          RecalculateMinMaxPointValues();
[8280]438          this.chart.Legends[series.Legend].ForeColor = Color.Black;
439          RecalculateAxesScale(chart.ChartAreas[0]);
440          UpdateYCursorInterval();
[7829]441        }
442      }
443    }
[8280]444
[12614]445    private void RecalculateMinMaxPointValues() {
446      yMin = xMin = double.MaxValue;
447      yMax = xMax = double.MinValue;
448      foreach (var s in chart.Series.Where(x => x.Enabled)) {
449        foreach (var p in s.Points) {
450          double x = p.XValue, y = p.YValues[0];
451          if (xMin > x) xMin = x;
452          if (xMax < x) xMax = x;
453          if (yMin > y) yMin = y;
454          if (yMax < y) yMax = y;
455        }
456      }
457    }
458
[8280]459    private void FillSeriesWithRowValues(Series series, ScatterPlotDataRow row) {
460      for (int i = 0; i < row.Points.Count; i++) {
461        var value = row.Points[i];
462        DataPoint point = new DataPoint();
463        if (IsInvalidValue(value.X) || IsInvalidValue(value.Y))
464          point.IsEmpty = true;
465        else {
466          point.XValue = value.X;
467          point.YValues = new double[] { value.Y };
468        }
469        series.Points.Add(point);
470      }
471    }
472
473    #region Helpers
474    private MarkerStyle ConvertPointStyle(ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle pointStyle) {
475      switch (pointStyle) {
476        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Circle:
477          return MarkerStyle.Circle;
478        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Cross:
479          return MarkerStyle.Cross;
480        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Diamond:
481          return MarkerStyle.Diamond;
482        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Square:
483          return MarkerStyle.Square;
484        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star4:
485          return MarkerStyle.Star4;
486        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star5:
487          return MarkerStyle.Star5;
488        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star6:
489          return MarkerStyle.Star6;
490        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star10:
491          return MarkerStyle.Star10;
492        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Triangle:
493          return MarkerStyle.Triangle;
494        default:
495          return MarkerStyle.None;
496      }
497    }
498
499    protected static bool IsInvalidValue(double x) {
500      return double.IsNaN(x) || x < (double)decimal.MinValue || x > (double)decimal.MaxValue;
501    }
502    #endregion
[7829]503  }
504}
Note: See TracBrowser for help on using the repository browser.