Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 4748 was 4748, checked in by swagner, 12 years ago

Worked on population diversity analysis (#1188)

File size: 19.1 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            foreach (IndexedItem<double> item in e.Items) {
283              var value = item.Value;
284              if (IsInvalidValue(item.Value)) {
285                DataPoint point = new DataPoint();
286                point.IsEmpty = true;
287                rowSeries.Points.Insert(item.Index, point);
288              } else {
289                rowSeries.Points.InsertY(item.Index, value);
290              }
291            }
292            UpdateYCursorInterval();
293          }
294        }
295      }
296    }
297    private void Values_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
298      if (InvokeRequired)
299        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved), sender, e);
300      else {
301        DataRow row = null;
302        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
303        if (row != null) {
304          Series rowSeries = chart.Series[row.Name];
305          if (!invisibleSeries.Contains(rowSeries)) {
306            List<DataPoint> points = new List<DataPoint>();
307            foreach (IndexedItem<double> item in e.Items)
308              points.Add(rowSeries.Points[item.Index]);
309            foreach (DataPoint point in points)
310              rowSeries.Points.Remove(point);
311            UpdateYCursorInterval();
312          }
313        }
314      }
315    }
316    private void Values_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
317      if (InvokeRequired)
318        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced), sender, e);
319      else {
320        DataRow row = null;
321        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
322        if (row != null) {
323          Series rowSeries = chart.Series[row.Name];
324          if (!invisibleSeries.Contains(rowSeries)) {
325            foreach (IndexedItem<double> item in e.Items) {
326              if (IsInvalidValue(item.Value))
327                rowSeries.Points[item.Index].IsEmpty = true;
328              else {
329                rowSeries.Points[item.Index].YValues = new double[] { item.Value };
330                rowSeries.Points[item.Index].IsEmpty = false;
331              }
332            }
333            UpdateYCursorInterval();
334          }
335        }
336      }
337    }
338    private void Values_ItemsMoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
339      if (InvokeRequired)
340        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved), sender, e);
341      else {
342        DataRow row = null;
343        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
344        if (row != null) {
345          Series rowSeries = chart.Series[row.Name];
346          if (!invisibleSeries.Contains(rowSeries)) {
347            foreach (IndexedItem<double> item in e.Items) {
348              if (IsInvalidValue(item.Value))
349                rowSeries.Points[item.Index].IsEmpty = true;
350              else {
351                rowSeries.Points[item.Index].YValues = new double[] { item.Value };
352                rowSeries.Points[item.Index].IsEmpty = false;
353              }
354            }
355            UpdateYCursorInterval();
356          }
357        }
358      }
359    }
360
361    private void Values_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
362      if (InvokeRequired)
363        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset), sender, e);
364      else {
365        DataRow row = null;
366        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
367        if (row != null) {
368          Series rowSeries = chart.Series[row.Name];
369          if (!invisibleSeries.Contains(rowSeries)) {
370            rowSeries.Points.Clear();
371            foreach (IndexedItem<double> item in e.Items) {
372              if (IsInvalidValue(item.Value))
373                rowSeries.Points[item.Index].IsEmpty = true;
374              else {
375                rowSeries.Points[item.Index].YValues = new double[] { item.Value };
376                rowSeries.Points[item.Index].IsEmpty = false;
377              }
378            }
379          }
380          UpdateYCursorInterval();
381        }
382      }
383    }
384    #endregion
385
386    #region Chart Events
387    private void chart_MouseDown(object sender, MouseEventArgs e) {
388      HitTestResult result = chart.HitTest(e.X, e.Y);
389      if (result.ChartElementType == ChartElementType.LegendItem) {
390        ToggleSeriesVisible(result.Series);
391      }
392    }
393
394    private void ToggleSeriesVisible(Series series) {
395      if (!invisibleSeries.Contains(series)) {
396        series.Points.Clear();
397        invisibleSeries.Add(series);
398      } else {
399        invisibleSeries.Remove(series);
400        if (Content != null) {
401
402          var row = (from r in Content.Rows
403                     where r.Name == series.Name
404                     select r).Single();
405          FillSeriesWithRowValues(series, row);
406          this.chart.Legends[series.Legend].ForeColor = Color.Black;
407          UpdateYCursorInterval();
408        }
409      }
410    }
411
412    private void FillSeriesWithRowValues(Series series, DataRow row) {
413      for (int i = 0; i < row.Values.Count; i++) {
414        var value = row.Values[i];
415        if (IsInvalidValue(value)) {
416          DataPoint point = new DataPoint();
417          point.IsEmpty = true;
418          series.Points.Add(point);
419        } else {
420          series.Points.Add(value);
421        }
422      }
423    }
424
425    private void chart_MouseMove(object sender, MouseEventArgs e) {
426      HitTestResult result = chart.HitTest(e.X, e.Y);
427      if (result.ChartElementType == ChartElementType.LegendItem)
428        this.Cursor = Cursors.Hand;
429      else
430        this.Cursor = Cursors.Default;
431    }
432    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
433      foreach (LegendItem legendItem in e.LegendItems) {
434        var series = chart.Series[legendItem.SeriesName];
435        if (series != null) {
436          bool seriesIsInvisible = invisibleSeries.Contains(series);
437          foreach (LegendCell cell in legendItem.Cells) {
438            cell.ForeColor = seriesIsInvisible ? Color.Gray : Color.Black;
439          }
440        }
441      }
442    }
443
444    #endregion
445
446    private bool IsInvalidValue(double x) {
447      return double.IsNaN(x) || x < (double)decimal.MinValue || x > (double)decimal.MaxValue;
448    }
449
450    private void exportChartToolStripMenuItem_Click(object sender, EventArgs e) {
451      if (saveFileDialog.ShowDialog() == DialogResult.OK) {
452        chart.SaveImage(saveFileDialog.FileName, ChartImageFormat.EmfDual);
453      }
454    }
455  }
456}
Note: See TracBrowser for help on using the repository browser.