Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Analysis.Views/3.3/DataTableView.cs @ 4778

Last change on this file since 4778 was 4778, checked in by swagner, 14 years ago

Worked on different start indexes for data tables (#925)

File size: 18.6 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 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.Core.Views;
30using HeuristicLab.MainForm;
31
32namespace HeuristicLab.Analysis.Views {
33  /// <summary>
34  /// The visual representation of a <see cref="Variable"/>.
35  /// </summary>
36  [View("DataTable View")]
37  [Content(typeof(DataTable), true)]
38  public sealed partial class DataTableView : NamedItemView {
39    private List<Series> invisibleSeries;
40    private Dictionary<IObservableList<double>, DataRow> valuesRowsTable;
41    /// <summary>
42    /// Gets or sets the variable to represent visually.
43    /// </summary>
44    /// <remarks>Uses property <see cref="ViewBase.Item"/> of base class <see cref="ViewBase"/>.
45    /// No own data storage present.</remarks>
46    public new DataTable Content {
47      get { return (DataTable)base.Content; }
48      set { base.Content = value; }
49    }
50
51    /// <summary>
52    /// Initializes a new instance of <see cref="VariableView"/> with caption "Variable".
53    /// </summary>
54    public DataTableView() {
55      InitializeComponent();
56      valuesRowsTable = new Dictionary<IObservableList<double>, DataRow>();
57      invisibleSeries = new List<Series>();
58      chart.CustomizeAllChartAreas();
59      chart.ChartAreas[0].CursorX.Interval = 1;
60    }
61
62    /// <summary>
63    /// Removes the eventhandlers from the underlying <see cref="Variable"/>.
64    /// </summary>
65    /// <remarks>Calls <see cref="ViewBase.RemoveItemEvents"/> of base class <see cref="ViewBase"/>.</remarks>
66    protected override void DeregisterContentEvents() {
67      foreach (DataRow row in Content.Rows)
68        DeregisterDataRowEvents(row);
69      Content.Rows.ItemsAdded -= new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsAdded);
70      Content.Rows.ItemsRemoved -= new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsRemoved);
71      Content.Rows.ItemsReplaced -= new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsReplaced);
72      Content.Rows.CollectionReset -= new CollectionItemsChangedEventHandler<DataRow>(Rows_CollectionReset);
73      base.DeregisterContentEvents();
74    }
75
76    /// <summary>
77    /// Adds eventhandlers to the underlying <see cref="Variable"/>.
78    /// </summary>
79    /// <remarks>Calls <see cref="ViewBase.AddItemEvents"/> of base class <see cref="ViewBase"/>.</remarks>
80    protected override void RegisterContentEvents() {
81      base.RegisterContentEvents();
82      Content.Rows.ItemsAdded += new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsAdded);
83      Content.Rows.ItemsRemoved += new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsRemoved);
84      Content.Rows.ItemsReplaced += new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsReplaced);
85      Content.Rows.CollectionReset += new CollectionItemsChangedEventHandler<DataRow>(Rows_CollectionReset);
86      foreach (DataRow row in Content.Rows)
87        RegisterDataRowEvents(row);
88    }
89
90    protected override void OnContentChanged() {
91      base.OnContentChanged();
92      invisibleSeries.Clear();
93      chart.Titles[0].Text = string.Empty;
94      chart.Series.Clear();
95      if (Content != null) {
96        chart.Titles[0].Text = Content.Name;
97        foreach (DataRow row in Content.Rows)
98          AddDataRow(row);
99      }
100    }
101
102    protected override void SetEnabledStateOfControls() {
103      base.SetEnabledStateOfControls();
104      chart.Enabled = Content != null;
105    }
106
107    private void AddDataRow(DataRow row) {
108      Series series = new Series(row.Name);
109      switch (row.VisualProperties.ChartType) {
110        case DataRowVisualProperties.DataRowChartType.Line:
111          series.ChartType = SeriesChartType.FastLine;
112          break;
113        case DataRowVisualProperties.DataRowChartType.Bars:
114          series.ChartType = SeriesChartType.Bar;
115          break;
116        case DataRowVisualProperties.DataRowChartType.Columns:
117          series.ChartType = SeriesChartType.Column;
118          break;
119        case DataRowVisualProperties.DataRowChartType.Points:
120          series.ChartType = SeriesChartType.FastPoint;
121          break;
122        default:
123          series.ChartType = SeriesChartType.FastPoint;
124          break;
125      }
126      series.YAxisType = row.VisualProperties.SecondYAxis ? AxisType.Secondary : AxisType.Primary;
127      if (row.VisualProperties.Color != Color.Empty) series.Color = row.VisualProperties.Color;
128      series.ToolTip = row.Name + " X = #INDEX, Y = #VAL";
129      FillSeriesWithRowValues(series, row);
130      chart.Series.Add(series);
131      chart.ChartAreas[0].RecalculateAxesScale();
132      UpdateYCursorInterval();
133    }
134
135    private void UpdateYCursorInterval() {
136      double interestingValuesRange = (from series in chart.Series
137                                       where series.Enabled
138                                       let values = (from point in series.Points
139                                                     where !point.IsEmpty
140                                                     select point.YValues[0])
141                                                     .DefaultIfEmpty(1.0)
142                                       let range = values.Max() - values.Min()
143                                       where range > 0.0
144                                       select range)
145                                       .DefaultIfEmpty(1.0)
146                                       .Min();
147
148      double digits = (int)Math.Log10(interestingValuesRange) - 3;
149      double yZoomInterval = Math.Pow(10, digits);
150      this.chart.ChartAreas[0].CursorY.Interval = yZoomInterval;
151    }
152
153    private void RemoveDataRow(DataRow row) {
154      Series series = chart.Series[row.Name];
155      chart.Series.Remove(series);
156      if (invisibleSeries.Contains(series))
157        invisibleSeries.Remove(series);
158      chart.ChartAreas[0].RecalculateAxesScale();
159    }
160
161    #region Content Events
162    private void RegisterDataRowEvents(DataRow row) {
163      row.NameChanged += new EventHandler(Row_NameChanged);
164      row.VisualPropertiesChanged += new EventHandler(Row_VisualPropertiesChanged);
165      valuesRowsTable.Add(row.Values, row);
166      row.Values.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded);
167      row.Values.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved);
168      row.Values.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced);
169      row.Values.ItemsMoved += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved);
170      row.Values.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset);
171    }
172    private void DeregisterDataRowEvents(DataRow row) {
173      row.Values.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded);
174      row.Values.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved);
175      row.Values.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced);
176      row.Values.ItemsMoved -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved);
177      row.Values.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset);
178      valuesRowsTable.Remove(row.Values);
179      row.VisualPropertiesChanged -= new EventHandler(Row_VisualPropertiesChanged);
180      row.NameChanged -= new EventHandler(Row_NameChanged);
181    }
182    protected override void Content_NameChanged(object sender, EventArgs e) {
183      if (InvokeRequired)
184        Invoke(new EventHandler(Content_NameChanged), sender, e);
185      else {
186        chart.Titles[0].Text = Content.Name;
187        base.Content_NameChanged(sender, e);
188      }
189    }
190    private void Rows_ItemsAdded(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
191      if (InvokeRequired)
192        Invoke(new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsAdded), sender, e);
193      else {
194        foreach (DataRow row in e.Items) {
195          AddDataRow(row);
196          RegisterDataRowEvents(row);
197        }
198      }
199    }
200    private void Rows_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
201      if (InvokeRequired)
202        Invoke(new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsRemoved), sender, e);
203      else {
204        foreach (DataRow row in e.Items) {
205          DeregisterDataRowEvents(row);
206          RemoveDataRow(row);
207        }
208      }
209    }
210    private void Rows_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
211      if (InvokeRequired)
212        Invoke(new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsReplaced), sender, e);
213      else {
214        foreach (DataRow row in e.OldItems) {
215          DeregisterDataRowEvents(row);
216          RemoveDataRow(row);
217        }
218        foreach (DataRow row in e.Items) {
219          AddDataRow(row);
220          RegisterDataRowEvents(row);
221        }
222      }
223    }
224    private void Rows_CollectionReset(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
225      if (InvokeRequired)
226        Invoke(new CollectionItemsChangedEventHandler<DataRow>(Rows_CollectionReset), sender, e);
227      else {
228        foreach (DataRow row in e.OldItems) {
229          DeregisterDataRowEvents(row);
230          RemoveDataRow(row);
231        }
232        foreach (DataRow row in e.Items) {
233          AddDataRow(row);
234          RegisterDataRowEvents(row);
235        }
236      }
237    }
238    private void Row_VisualPropertiesChanged(object sender, EventArgs e) {
239      if (InvokeRequired)
240        Invoke(new EventHandler(Row_VisualPropertiesChanged), sender, e);
241      else {
242        DataRow row = (DataRow)sender;
243        switch (row.VisualProperties.ChartType) {
244          case DataRowVisualProperties.DataRowChartType.Line:
245            chart.Series[row.Name].ChartType = SeriesChartType.FastLine;
246            break;
247          case DataRowVisualProperties.DataRowChartType.Bars:
248            chart.Series[row.Name].ChartType = SeriesChartType.Bar;
249            break;
250          case DataRowVisualProperties.DataRowChartType.Columns:
251            chart.Series[row.Name].ChartType = SeriesChartType.Column;
252            break;
253          case DataRowVisualProperties.DataRowChartType.Points:
254            chart.Series[row.Name].ChartType = SeriesChartType.FastPoint;
255            break;
256          default:
257            chart.Series[row.Name].ChartType = SeriesChartType.FastPoint;
258            break;
259        }
260        chart.Series[row.Name].YAxisType = row.VisualProperties.SecondYAxis ? AxisType.Secondary : AxisType.Primary;
261        if (row.VisualProperties.Color != Color.Empty) chart.Series[row.Name].Color = row.VisualProperties.Color;
262        chart.ChartAreas[0].RecalculateAxesScale();
263      }
264    }
265    private void Row_NameChanged(object sender, EventArgs e) {
266      if (InvokeRequired)
267        Invoke(new EventHandler(Row_NameChanged), sender, e);
268      else {
269        DataRow row = (DataRow)sender;
270        chart.Series[row.Name].Name = row.Name;
271      }
272    }
273    private void Values_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
274      if (InvokeRequired)
275        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded), sender, e);
276      else {
277        DataRow row = null;
278        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
279        if (row != null) {
280          Series rowSeries = chart.Series[row.Name];
281          if (!invisibleSeries.Contains(rowSeries)) {
282            rowSeries.Points.Clear();
283            FillSeriesWithRowValues(rowSeries, row);
284            //foreach (IndexedItem<double> item in e.Items) {
285            //  var value = item.Value;
286            //  DataPoint point = new DataPoint();
287            //  point.XValue = row.VisualProperties.StartIndexZero ? item.Index : item.Index + 1;
288            //  if (IsInvalidValue(item.Value))
289            //    point.IsEmpty = true;
290            //  else
291            //    point.YValues = new double[] { value };
292            //  rowSeries.Points.Add(point);
293            //}
294            UpdateYCursorInterval();
295          }
296        }
297      }
298    }
299    private void Values_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
300      if (InvokeRequired)
301        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved), sender, e);
302      else {
303        DataRow row = null;
304        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
305        if (row != null) {
306          Series rowSeries = chart.Series[row.Name];
307          if (!invisibleSeries.Contains(rowSeries)) {
308            rowSeries.Points.Clear();
309            FillSeriesWithRowValues(rowSeries, row);
310            //List<DataPoint> points = new List<DataPoint>();
311            //foreach (IndexedItem<double> item in e.Items)
312            //  points.Add(rowSeries.Points[item.Index]);
313            //foreach (DataPoint point in points)
314            //  rowSeries.Points.Remove(point);
315            UpdateYCursorInterval();
316          }
317        }
318      }
319    }
320    private void Values_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
321      if (InvokeRequired)
322        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced), sender, e);
323      else {
324        DataRow row = null;
325        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
326        if (row != null) {
327          Series rowSeries = chart.Series[row.Name];
328          if (!invisibleSeries.Contains(rowSeries)) {
329            foreach (IndexedItem<double> item in e.Items) {
330              if (IsInvalidValue(item.Value))
331                rowSeries.Points[item.Index].IsEmpty = true;
332              else {
333                rowSeries.Points[item.Index].YValues = new double[] { item.Value };
334                rowSeries.Points[item.Index].IsEmpty = false;
335              }
336            }
337            UpdateYCursorInterval();
338          }
339        }
340      }
341    }
342    private void Values_ItemsMoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
343      if (InvokeRequired)
344        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved), sender, e);
345      else {
346        DataRow row = null;
347        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
348        if (row != null) {
349          Series rowSeries = chart.Series[row.Name];
350          if (!invisibleSeries.Contains(rowSeries)) {
351            rowSeries.Points.Clear();
352            FillSeriesWithRowValues(rowSeries, row);
353            UpdateYCursorInterval();
354          }
355        }
356      }
357    }
358
359    private void Values_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
360      if (InvokeRequired)
361        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset), sender, e);
362      else {
363        DataRow row = null;
364        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
365        if (row != null) {
366          Series rowSeries = chart.Series[row.Name];
367          if (!invisibleSeries.Contains(rowSeries)) {
368            rowSeries.Points.Clear();
369            FillSeriesWithRowValues(rowSeries, row);
370            UpdateYCursorInterval();
371          }
372        }
373      }
374    }
375    #endregion
376
377    #region Chart Events
378    private void chart_MouseDown(object sender, MouseEventArgs e) {
379      HitTestResult result = chart.HitTest(e.X, e.Y);
380      if (result.ChartElementType == ChartElementType.LegendItem) {
381        ToggleSeriesVisible(result.Series);
382      }
383    }
384
385    private void ToggleSeriesVisible(Series series) {
386      if (!invisibleSeries.Contains(series)) {
387        series.Points.Clear();
388        invisibleSeries.Add(series);
389      } else {
390        invisibleSeries.Remove(series);
391        if (Content != null) {
392
393          var row = (from r in Content.Rows
394                     where r.Name == series.Name
395                     select r).Single();
396          FillSeriesWithRowValues(series, row);
397          this.chart.Legends[series.Legend].ForeColor = Color.Black;
398          UpdateYCursorInterval();
399        }
400      }
401    }
402
403    private void FillSeriesWithRowValues(Series series, DataRow row) {
404      for (int i = 0; i < row.Values.Count; i++) {
405        var value = row.Values[i];
406        DataPoint point = new DataPoint();
407        point.XValue = row.VisualProperties.StartIndexZero ? i : i + 1;
408        if (IsInvalidValue(value))
409          point.IsEmpty = true;
410        else
411          point.YValues = new double[] { value };
412        series.Points.Add(point);
413      }
414    }
415
416    private void chart_MouseMove(object sender, MouseEventArgs e) {
417      HitTestResult result = chart.HitTest(e.X, e.Y);
418      if (result.ChartElementType == ChartElementType.LegendItem)
419        this.Cursor = Cursors.Hand;
420      else
421        this.Cursor = Cursors.Default;
422    }
423    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
424      foreach (LegendItem legendItem in e.LegendItems) {
425        var series = chart.Series[legendItem.SeriesName];
426        if (series != null) {
427          bool seriesIsInvisible = invisibleSeries.Contains(series);
428          foreach (LegendCell cell in legendItem.Cells) {
429            cell.ForeColor = seriesIsInvisible ? Color.Gray : Color.Black;
430          }
431        }
432      }
433    }
434    #endregion
435
436    private bool IsInvalidValue(double x) {
437      return double.IsNaN(x) || x < (double)decimal.MinValue || x > (double)decimal.MaxValue;
438    }
439  }
440}
Note: See TracBrowser for help on using the repository browser.