Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionErrorCharacteristicsCurveView.cs @ 8102

Last change on this file since 8102 was 8102, checked in by sforsten, 12 years ago

#1811: added tool tip to explain that a model can be opened by double-clicking

File size: 9.7 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2012 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.Linq;
25using System.Windows.Forms;
26using System.Windows.Forms.DataVisualization.Charting;
27using HeuristicLab.MainForm;
28
29namespace HeuristicLab.Problems.DataAnalysis.Views {
30  [View("Error Characteristics Curve")]
31  [Content(typeof(IRegressionSolution))]
32  public partial class RegressionSolutionErrorCharacteristicsCurveView : DataAnalysisSolutionEvaluationView {
33    protected const string TrainingSamples = "Training";
34    protected const string TestSamples = "Test";
35    protected const string AllSamples = "All Samples";
36
37    public RegressionSolutionErrorCharacteristicsCurveView()
38      : base() {
39      InitializeComponent();
40
41      cmbSamples.Items.Add(TrainingSamples);
42      cmbSamples.Items.Add(TestSamples);
43      cmbSamples.Items.Add(AllSamples);
44
45      cmbSamples.SelectedIndex = 0;
46
47      chart.CustomizeAllChartAreas();
48      chart.ChartAreas[0].AxisX.Title = "Absolute Error";
49      chart.ChartAreas[0].AxisX.Minimum = 0.0;
50      chart.ChartAreas[0].AxisX.Maximum = 1.0;
51      chart.ChartAreas[0].AxisX.IntervalAutoMode = IntervalAutoMode.VariableCount;
52      chart.ChartAreas[0].CursorX.Interval = 0.01;
53
54      chart.ChartAreas[0].AxisY.Title = "Number of Samples";
55      chart.ChartAreas[0].AxisY.Minimum = 0.0;
56      chart.ChartAreas[0].AxisY.Maximum = 1.0;
57      chart.ChartAreas[0].AxisY.MajorGrid.Interval = 0.2;
58      chart.ChartAreas[0].CursorY.Interval = 0.01;
59    }
60
61    public new IRegressionSolution Content {
62      get { return (IRegressionSolution)base.Content; }
63      set { base.Content = value; }
64    }
65    public IRegressionProblemData ProblemData {
66      get {
67        if (Content == null) return null;
68        return Content.ProblemData;
69      }
70    }
71
72    protected override void RegisterContentEvents() {
73      base.RegisterContentEvents();
74      Content.ModelChanged += new EventHandler(Content_ModelChanged);
75      Content.ProblemDataChanged += new EventHandler(Content_ProblemDataChanged);
76    }
77    protected override void DeregisterContentEvents() {
78      base.DeregisterContentEvents();
79      Content.ModelChanged -= new EventHandler(Content_ModelChanged);
80      Content.ProblemDataChanged -= new EventHandler(Content_ProblemDataChanged);
81    }
82
83    protected virtual void Content_ModelChanged(object sender, EventArgs e) {
84      if (InvokeRequired) Invoke((Action<object, EventArgs>)Content_ModelChanged, sender, e);
85      else UpdateChart();
86    }
87    protected virtual void Content_ProblemDataChanged(object sender, EventArgs e) {
88      if (InvokeRequired) Invoke((Action<object, EventArgs>)Content_ProblemDataChanged, sender, e);
89      else {
90        UpdateChart();
91      }
92    }
93    protected override void OnContentChanged() {
94      base.OnContentChanged();
95      UpdateChart();
96    }
97
98    protected virtual void UpdateChart() {
99      chart.Series.Clear();
100      chart.Annotations.Clear();
101      if (Content == null) return;
102
103      var constantModel = CreateConstantModel();
104      var originalValues = GetOriginalValues().ToList();
105      var baselineEstimatedValues = GetEstimatedValues(constantModel);
106      var baselineResiduals = GetResiduals(originalValues, baselineEstimatedValues);
107
108      baselineResiduals.Sort();
109      chart.ChartAreas[0].AxisX.Maximum = Math.Ceiling(baselineResiduals.Last());
110      chart.ChartAreas[0].CursorX.Interval = baselineResiduals.First() / 100;
111
112      Series baselineSeries = new Series("Baseline");
113      baselineSeries.ChartType = SeriesChartType.FastLine;
114      UpdateSeries(baselineResiduals, baselineSeries);
115      baselineSeries.ToolTip = "Area over Curve: " + CalculateAreaOverCurve(baselineSeries);
116      baselineSeries.Tag = constantModel;
117      chart.Series.Add(baselineSeries);
118
119      AddRegressionSolution(Content);
120    }
121
122    protected void AddRegressionSolution(IRegressionSolution solution) {
123      if (chart.Series.Any(s => s.Name == solution.Name)) return;
124
125      Series solutionSeries = new Series(solution.Name);
126      solutionSeries.Tag = solution;
127      solutionSeries.ChartType = SeriesChartType.FastLine;
128      var estimatedValues = GetResiduals(GetOriginalValues(), GetEstimatedValues(solution));
129      UpdateSeries(estimatedValues, solutionSeries);
130      solutionSeries.ToolTip = "Area over Curve: " + CalculateAreaOverCurve(solutionSeries);
131      chart.Series.Add(solutionSeries);
132    }
133
134    protected void UpdateSeries(List<double> residuals, Series series) {
135      series.Points.Clear();
136      residuals.Sort();
137      if (!residuals.Any() || residuals.All(double.IsNaN)) return;
138
139      series.Points.AddXY(0, 0);
140      for (int i = 0; i < residuals.Count; i++) {
141        var point = new DataPoint();
142        if (residuals[i] > chart.ChartAreas[0].AxisX.Maximum) {
143          point.XValue = chart.ChartAreas[0].AxisX.Maximum;
144          point.YValues[0] = ((double)i) / residuals.Count;
145          point.ToolTip = "Error: " + point.XValue + "\n" + "Samples: " + point.YValues[0];
146          series.Points.Add(point);
147          break;
148        }
149
150        point.XValue = residuals[i];
151        point.YValues[0] = ((double)i + 1) / residuals.Count;
152        point.ToolTip = "Error: " + point.XValue + "\n" + "Samples: " + point.YValues[0];
153        series.Points.Add(point);
154      }
155
156      if (series.Points.Last().XValue < chart.ChartAreas[0].AxisX.Maximum) {
157        var point = new DataPoint();
158        point.XValue = chart.ChartAreas[0].AxisX.Maximum;
159        point.YValues[0] = 1;
160        point.ToolTip = "Error: " + point.XValue + "\n" + "Samples: " + point.YValues[0];
161        series.Points.Add(point);
162      }
163    }
164
165    protected IEnumerable<double> GetOriginalValues() {
166      IEnumerable<double> originalValues;
167      switch (cmbSamples.SelectedItem.ToString()) {
168        case TrainingSamples:
169          originalValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndizes);
170          break;
171        case TestSamples:
172          originalValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TestIndizes);
173          break;
174        case AllSamples:
175          originalValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable);
176          break;
177        default:
178          throw new NotSupportedException();
179      }
180      return originalValues;
181    }
182
183    protected IEnumerable<double> GetEstimatedValues(IRegressionSolution solution) {
184      IEnumerable<double> estimatedValues;
185      switch (cmbSamples.SelectedItem.ToString()) {
186        case TrainingSamples:
187          estimatedValues = solution.EstimatedTrainingValues;
188          break;
189        case TestSamples:
190          estimatedValues = solution.EstimatedTestValues;
191          break;
192        case AllSamples:
193          estimatedValues = solution.EstimatedValues;
194          break;
195        default:
196          throw new NotSupportedException();
197      }
198      return estimatedValues;
199    }
200
201    protected virtual List<double> GetResiduals(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues) {
202      return originalValues.Zip(estimatedValues, (x, y) => Math.Abs(x - y)).ToList();
203    }
204
205    private double CalculateAreaOverCurve(Series series) {
206      if (series.Points.Count < 1) return 0;
207
208      double auc = 0.0;
209      for (int i = 1; i < series.Points.Count; i++) {
210        double width = series.Points[i].XValue - series.Points[i - 1].XValue;
211        double y1 = 1 - series.Points[i - 1].YValues[0];
212        double y2 = 1 - series.Points[i].YValues[0];
213
214        auc += (y1 + y2) * width / 2;
215      }
216
217      return auc;
218    }
219
220    protected void cmbSamples_SelectedIndexChanged(object sender, EventArgs e) {
221      if (InvokeRequired) Invoke((Action<object, EventArgs>)cmbSamples_SelectedIndexChanged, sender, e);
222      else UpdateChart();
223    }
224
225    #region Baseline
226    private void Chart_MouseDoubleClick(object sender, MouseEventArgs e) {
227      HitTestResult result = chart.HitTest(e.X, e.Y);
228      if (result.ChartElementType != ChartElementType.LegendItem) return;
229
230      MainFormManager.MainForm.ShowContent((IRegressionSolution)result.Series.Tag);
231    }
232
233    private IRegressionSolution CreateConstantModel() {
234      double averageTrainingTarget = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndizes).Average();
235      var solution = new ConstantRegressionModel(averageTrainingTarget).CreateRegressionSolution(ProblemData);
236      solution.Name = "Baseline";
237      return solution;
238    }
239    #endregion
240
241    private void chart_MouseMove(object sender, MouseEventArgs e) {
242      HitTestResult result = chart.HitTest(e.X, e.Y);
243      if (result.ChartElementType == ChartElementType.LegendItem) {
244        Cursor = Cursors.Hand;
245        LegendToolTip.SetToolTip(chart, "Double-click to open model");
246      } else {
247        Cursor = Cursors.Default;
248        LegendToolTip.RemoveAll();
249      }
250    }
251  }
252}
Note: See TracBrowser for help on using the repository browser.