Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Classification/HeuristicLab.Problems.DataAnalysis.Classfication.Views/3.3/SymbolicClassificationSolutionView.cs @ 4367

Last change on this file since 4367 was 4367, checked in by mkommend, 14 years ago

Added classification views (ticket #939)

File size: 10.2 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.MainForm;
29using HeuristicLab.MainForm.WindowsForms;
30
31namespace HeuristicLab.Problems.DataAnalysis.Classification.Views {
32  [View("Symbolic Classification View")]
33  [Content(typeof(SymbolicClassificationSolution), true)]
34  public sealed partial class SymbolicClassificationSolutionView : AsynchronousContentView {
35    private const double TrainingAxisValue = 0.0;
36    private const double TestAxisValue = 10.0;
37    private const double TrainingTestBorder = (TestAxisValue - TrainingAxisValue) / 2;
38    private const string TrainingLabelText = "Training Samples";
39    private const string TestLabelText = "Test Samples";
40
41    public new SymbolicClassificationSolution Content {
42      get { return (SymbolicClassificationSolution)base.Content; }
43      set { base.Content = value; }
44    }
45
46    private Dictionary<double, Series> classValueSeriesMapping;
47    private Random random;
48    private bool updateInProgress;
49
50    public SymbolicClassificationSolutionView()
51      : base() {
52      InitializeComponent();
53
54      classValueSeriesMapping = new Dictionary<double, Series>();
55      random = new Random();
56      updateInProgress = false;
57
58      this.chart.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
59      this.chart.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
60      this.chart.ChartAreas[0].AxisX.Minimum = TrainingAxisValue - TrainingTestBorder;
61      this.chart.ChartAreas[0].AxisX.Maximum = TestAxisValue + TrainingTestBorder;
62      AddCustomLabelToAxis(this.chart.ChartAreas[0].AxisX);
63
64      this.chart.ChartAreas[0].AxisY.Title = "Estimated Values";
65      this.chart.ChartAreas[0].CursorY.IsUserSelectionEnabled = true;
66    }
67
68    private void AddCustomLabelToAxis(Axis axis) {
69      CustomLabel trainingLabel = new CustomLabel();
70      trainingLabel.Text = TrainingLabelText;
71      trainingLabel.GridTicks = GridTickTypes.TickMark;
72      trainingLabel.FromPosition = TrainingAxisValue - TrainingTestBorder;
73      trainingLabel.ToPosition = TrainingAxisValue + TrainingTestBorder;
74      axis.CustomLabels.Add(trainingLabel);
75
76      CustomLabel testLabel = new CustomLabel();
77      testLabel.Text = TestLabelText;
78      testLabel.GridTicks = GridTickTypes.TickMark;
79      testLabel.FromPosition = TestAxisValue - TrainingTestBorder;
80      testLabel.ToPosition = TestAxisValue + TrainingTestBorder;
81      axis.CustomLabels.Add(testLabel);
82    }
83
84    protected override void RegisterContentEvents() {
85      base.RegisterContentEvents();
86      Content.EstimatedValuesChanged += new EventHandler(Content_EstimatedValuesChanged);
87      Content.ProblemDataChanged += new EventHandler(Content_ProblemDataChanged);
88      Content.ThresholdsChanged += new EventHandler(Content_ThresholdsChanged);
89    }
90    protected override void DeregisterContentEvents() {
91      base.DeregisterContentEvents();
92      Content.EstimatedValuesChanged -= new EventHandler(Content_EstimatedValuesChanged);
93      Content.ProblemDataChanged -= new EventHandler(Content_ProblemDataChanged);
94      Content.ThresholdsChanged -= new EventHandler(Content_ThresholdsChanged);
95    }
96
97    private void Content_ProblemDataChanged(object sender, EventArgs e) {
98      UpdateChart();
99    }
100    private void Content_EstimatedValuesChanged(object sender, EventArgs e) {
101      UpdateChart();
102    }
103    private void Content_ThresholdsChanged(object sender, EventArgs e) {
104      AddThresholds();
105    }
106    protected override void OnContentChanged() {
107      base.OnContentChanged();
108      UpdateChart();
109    }
110
111    private void UpdateChart() {
112      if (InvokeRequired) Invoke((Action)UpdateChart);
113      else if (!updateInProgress) {
114        updateInProgress = true;
115        chart.Series.Clear();
116        classValueSeriesMapping.Clear();
117        if (Content != null) {
118          IEnumerator<string> classNameEnumerator = Content.ProblemData.ClassNames.GetEnumerator();
119          IEnumerator<double> classValueEnumerator = Content.ProblemData.SortedClassValues.GetEnumerator();
120          while (classNameEnumerator.MoveNext() && classValueEnumerator.MoveNext()) {
121            Series series = new Series(classNameEnumerator.Current);
122            series.ChartType = SeriesChartType.FastPoint;
123            series.Tag = classValueEnumerator.Current;
124            chart.Series.Add(series);
125            classValueSeriesMapping.Add(classValueEnumerator.Current, series);
126            FillSeriesWithDataPoints(series);
127          }
128          AddThresholds();
129        }
130        updateInProgress = false;
131      }
132    }
133
134    private void FillSeriesWithDataPoints(Series series) {
135      int row = Content.ProblemData.TrainingSamplesStart.Value;
136      foreach (double estimatedValue in Content.EstimatedTrainingValues) {
137        double targetValue = Content.ProblemData.Dataset[Content.ProblemData.TargetVariable.Value, row];
138        if (targetValue == (double)series.Tag) {
139          double jitterValue = random.NextDouble() * 2.0 - 1.0;
140          DataPoint point = new DataPoint();
141          point.XValue = TrainingAxisValue + 0.01 * jitterValue * JitterTrackBar.Value * (TrainingTestBorder * 0.9);
142          point.YValues[0] = estimatedValue;
143          point.Tag = new KeyValuePair<double, double>(TrainingAxisValue, jitterValue);
144          series.Points.Add(point);
145        }
146        row++;
147      }
148
149      row = Content.ProblemData.TestSamplesStart.Value;
150      foreach (double estimatedValue in Content.EstimatedTestValues) {
151        double targetValue = Content.ProblemData.Dataset[Content.ProblemData.TargetVariable.Value, row];
152        if (targetValue == (double)series.Tag) {
153          double jitterValue = random.NextDouble() * 2.0 - 1.0;
154          DataPoint point = new DataPoint();
155          point.XValue = TestAxisValue + 0.01 * jitterValue * JitterTrackBar.Value * (TrainingTestBorder * 0.9);
156          point.YValues[0] = estimatedValue;
157          point.Tag = new KeyValuePair<double, double>(TestAxisValue, jitterValue);
158          series.Points.Add(point);
159        }
160        row++;
161      }
162    }
163
164    private void AddThresholds() {
165      chart.Annotations.Clear();
166      int classIndex = 1;
167      foreach (double threshold in Content.Thresholds) {
168        if (!double.IsInfinity(threshold)) {
169          HorizontalLineAnnotation annotation = new HorizontalLineAnnotation();
170          annotation.AllowMoving = true;
171          annotation.AllowResizing = false;
172          annotation.LineWidth = 2;
173          annotation.LineColor = Color.Red;
174
175          annotation.IsInfinitive = true;
176          annotation.ClipToChartArea = chart.ChartAreas[0].Name;
177          annotation.Tag = classIndex;  //save classIndex as Tag to avoid moving the threshold accross class bounderies
178
179          annotation.AxisX = chart.ChartAreas[0].AxisX;
180          annotation.AxisY = chart.ChartAreas[0].AxisY;
181          annotation.Y = threshold;
182
183          chart.Annotations.Add(annotation);
184          classIndex++;
185        }
186      }
187    }
188
189    private void JitterTrackBar_ValueChanged(object sender, EventArgs e) {
190      foreach (Series series in chart.Series) {
191        foreach (DataPoint point in series.Points) {
192          double value = ((KeyValuePair<double, double>)point.Tag).Key;
193          double jitterValue = ((KeyValuePair<double, double>)point.Tag).Value; ;
194          point.XValue = value + 0.01 * jitterValue * JitterTrackBar.Value * (TrainingTestBorder * 0.9);
195        }
196      }
197    }
198
199    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
200      foreach (LegendItem legendItem in e.LegendItems) {
201        var series = chart.Series[legendItem.SeriesName];
202        if (series != null) {
203          bool seriesIsInvisible = series.Points.Count == 0;
204          foreach (LegendCell cell in legendItem.Cells)
205            cell.ForeColor = seriesIsInvisible ? Color.Gray : Color.Black;
206        }
207      }
208    }
209
210    private void chart_MouseMove(object sender, MouseEventArgs e) {
211      HitTestResult result = chart.HitTest(e.X, e.Y);
212      if (result.ChartElementType == ChartElementType.LegendItem)
213        this.Cursor = Cursors.Hand;
214      else
215        this.Cursor = Cursors.Default;
216    }
217
218    private void ToggleSeries(Series series) {
219      if (series.Points.Count == 0)
220        FillSeriesWithDataPoints(series);
221      else
222        series.Points.Clear();
223    }
224
225    private void chart_MouseDown(object sender, MouseEventArgs e) {
226      HitTestResult result = chart.HitTest(e.X, e.Y);
227      if (result.ChartElementType == ChartElementType.LegendItem) {
228        if (result.Series != null) ToggleSeries(result.Series);
229      }
230    }
231
232    private void chart_AnnotationPositionChanging(object sender, AnnotationPositionChangingEventArgs e) {
233      int classIndex = (int)e.Annotation.Tag;
234
235      double classValue = Content.ProblemData.SortedClassValues.ElementAt(classIndex);
236      if (e.NewLocationY >= classValue)
237        e.NewLocationY = classValue;
238
239      classValue = Content.ProblemData.SortedClassValues.ElementAt(classIndex - 1);
240      if (e.NewLocationY <= classValue)
241        e.NewLocationY = classValue;
242
243      double[] thresholds = Content.Thresholds.ToArray();
244      thresholds[classIndex] = e.NewLocationY;
245      Content.Thresholds = thresholds;
246    }
247  }
248}
Note: See TracBrowser for help on using the repository browser.