Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 4849 was 4849, checked in by gkronber, 14 years ago

Reviewed classes AlleleFrequencyAnalyzer, TSPAlleleFrequencyAnalyzer, Allele, AlleleFrequencyCollection, AlleleFrequencyCollectionHistory, AlleleFrequencyView, AlleleFrequencyCollectionView, AlleleFrequencyCollectionHistoryView and MovieView and made some minor changes. #1234

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