Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/GaussianProcessRegressionSolutionInteractiveRangeEstimatorView.cs @ 13816

Last change on this file since 13816 was 13816, checked in by pfleck, 9 years ago

#2597:

  • Fixed typo in class/filename.
  • Added new control that shows density information adjacent to the trackbar.
File size: 12.9 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 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.Data;
30using HeuristicLab.MainForm;
31using HeuristicLab.MainForm.WindowsForms;
32using HeuristicLab.Problems.DataAnalysis;
33using HeuristicLab.Problems.DataAnalysis.Views;
34using HeuristicLab.Visualization.ChartControlsExtensions;
35
36namespace HeuristicLab.Algorithms.DataAnalysis.Views {
37  [View("Interactive Estimator")]
38  [Content(typeof(GaussianProcessRegressionSolution))]
39  public partial class GaussianProcessRegressionSolutionInteractiveRangeEstimatorView
40    : DataAnalysisSolutionEvaluationView {
41
42    private const int DrawingSteps = 1000;
43
44    private const string EstimatedMeanSeriesName = "Estimated Mean";
45    private const string EstimatedVarianceSeriesName = "95% Conficence Interval";
46
47    private readonly List<string> dimensionNames;
48    private readonly ObservableList<DensityTrackbar> dimensionTrackbars;
49
50    private int ActiveDimension {
51      get { return dimensionTrackbars.FindIndex(tb => tb.Checked); }
52    }
53
54    public new GaussianProcessRegressionSolution Content {
55      get { return (GaussianProcessRegressionSolution)base.Content; }
56      set { base.Content = value; }
57    }
58
59    public GaussianProcessRegressionSolutionInteractiveRangeEstimatorView()
60      : base() {
61      dimensionNames = new List<string>();
62
63      dimensionTrackbars = new ObservableList<DensityTrackbar>();
64      dimensionTrackbars.ItemsAdded += (sender, args) => {
65        ForEach(args.Items.Select(i => i.Value), RegisterEvents);
66      };
67      dimensionTrackbars.ItemsRemoved += (sender, args) => {
68        ForEach(args.Items.Select(i => i.Value), DeregisterEvents);
69      };
70      dimensionTrackbars.CollectionReset += (sender, args) => {
71        ForEach(args.OldItems.Select(i => i.Value), DeregisterEvents);
72        ForEach(args.Items.Select(i => i.Value), RegisterEvents);
73      };
74
75
76      InitializeComponent();
77
78      // Avoid additional horizontal scrollbar
79      var vertScrollWidth = SystemInformation.VerticalScrollBarWidth;
80      tableLayoutPanel.Padding = new Padding(0, 0, vertScrollWidth, 0);
81
82      // Configure axis
83      chart.CustomizeAllChartAreas();
84      chart.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
85      chart.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
86      chart.ChartAreas[0].CursorX.Interval = 1;
87
88      chart.ChartAreas[0].CursorY.IsUserSelectionEnabled = true;
89      chart.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
90      chart.ChartAreas[0].CursorY.Interval = 0;
91    }
92
93    private void RedrawChart() {
94      chart.Series.Clear();
95      chart.ChartAreas[0].AxisX.StripLines.Clear();
96      if (Content == null || ActiveDimension < 0) return;
97
98      double minX = dimensionTrackbars[ActiveDimension].Limits.Lower;
99      double maxX = dimensionTrackbars[ActiveDimension].Limits.Upper;
100      decimal stepSize = (decimal)((maxX - minX) / DrawingSteps);
101
102      // Build dataset
103      var activeXs = Enumerable.Range(0, DrawingSteps).Select(i => (decimal)minX + i * stepSize).ToList();
104      var fixedXs = dimensionTrackbars.Select(tb => tb.Value).ToList();
105      var values = new double[DrawingSteps, dimensionNames.Count];
106      for (int r = 0; r < DrawingSteps; r++) {
107        for (int c = 0; c < dimensionNames.Count; c++) {
108          values[r, c] = (double)(c == ActiveDimension ? activeXs[r] : fixedXs[c]);
109        }
110      }
111      var dataset = new Dataset(dimensionNames, values);
112
113      // Estimations
114      var model = Content.Model;
115      var means = model.GetEstimatedValues(dataset, Enumerable.Range(0, DrawingSteps)).ToList();
116      var variances = model.GetEstimatedVariance(dataset, Enumerable.Range(0, DrawingSteps)).ToList();
117
118      // Charting config
119      chart.ChartAreas[0].AxisX.Minimum = minX;
120      chart.ChartAreas[0].AxisX.Maximum = maxX;
121      chart.ChartAreas[0].AxisX.Interval = (maxX - minX) / 10;
122
123      // ToDo only databind and put config in codebehind
124      chart.Series.Add(EstimatedVarianceSeriesName);
125      chart.Series[EstimatedVarianceSeriesName].LegendText = EstimatedVarianceSeriesName;
126      chart.Series[EstimatedVarianceSeriesName].ChartType = SeriesChartType.Range;
127      chart.Series[EstimatedVarianceSeriesName].EmptyPointStyle.Color = chart.Series[EstimatedVarianceSeriesName].Color;
128
129      chart.Series.Add(EstimatedMeanSeriesName);
130      chart.Series[EstimatedMeanSeriesName].LegendText = EstimatedMeanSeriesName;
131      chart.Series[EstimatedMeanSeriesName].ChartType = SeriesChartType.FastLine;
132
133      // Charting databind
134      var lower = means.Zip(variances, GetLowerConfBound).ToList();
135      var upper = means.Zip(variances, GetUpperConfBound).ToList();
136      chart.Series[EstimatedVarianceSeriesName].Points.DataBindXY(activeXs, lower, upper);
137      chart.Series[EstimatedMeanSeriesName].Points.DataBindXY(activeXs, means);
138
139      // Update StripLines
140      var trainingValues = Content.ProblemData.Dataset.GetDoubleValues(dimensionNames[ActiveDimension],
141        Content.ProblemData.TrainingIndices);
142      var trainingRange = new DoubleRange(trainingValues.Min(), trainingValues.Max());
143      if (minX < trainingRange.Start)
144        CreateAndAddStripLine(minX, trainingRange.Start, Color.FromArgb(40, 223, 58, 2), Color.Transparent);
145      if (maxX > trainingRange.End)
146        CreateAndAddStripLine(trainingRange.End, maxX, Color.FromArgb(40, 223, 58, 2), Color.Transparent);
147
148      // Update axis description
149      chart.ChartAreas[0].AxisX.Title = dimensionNames[ActiveDimension];
150    }
151
152    private void CreateAndAddStripLine(double start, double end, Color color, Color secondColor) {
153      StripLine stripLine = new StripLine {
154        BackColor = color,
155        BackSecondaryColor = secondColor,
156        StripWidth = end - start,
157        IntervalOffset = start
158      };
159      chart.ChartAreas[0].AxisX.StripLines.Add(stripLine);
160    }
161
162    private void UpdateConfigurationControls() {
163      tableLayoutPanel.SuspendRepaint();
164      tableLayoutPanel.SuspendLayout();
165
166      tableLayoutPanel.RowCount = 0;
167      tableLayoutPanel.Controls.Clear();
168
169      dimensionNames.Clear();
170      dimensionTrackbars.Clear();
171
172      if (Content == null) {
173        tableLayoutPanel.ResumeLayout(true);
174        tableLayoutPanel.ResumeRepaint(true);
175        return;
176      }
177
178      dimensionNames.AddRange(Content.ProblemData.AllowedInputVariables);
179      var ranges = new List<DoubleLimit>();
180      for (int i = 0; i < dimensionNames.Count; i++) {
181        var values = Content.ProblemData.Dataset.GetDoubleValues(dimensionNames[i], Content.ProblemData.AllIndices);
182        double min, max, interval;
183        ChartUtil.CalculateAxisInterval(values.Min(), values.Max(), 10, out min, out max, out interval);
184        ranges.Add(new DoubleLimit(min, max));
185      }
186
187      tableLayoutPanel.RowCount = dimensionNames.Count;
188      while (tableLayoutPanel.RowStyles.Count < dimensionNames.Count)
189        tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.AutoSize));
190
191      for (int i = 0; i < dimensionNames.Count; i++) {
192        var name = dimensionNames[i];
193        var trainingData =
194          Content.ProblemData.Dataset.GetDoubleValues(name, Content.ProblemData.TrainingIndices).ToList();
195
196        var dimensionTrackbar = new DensityTrackbar(name, ranges[i], trainingData);
197
198        // events registered automatically
199        dimensionTrackbars.Add(dimensionTrackbar);
200
201        dimensionTrackbar.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
202        tableLayoutPanel.Controls.Add(dimensionTrackbar, 0, i);
203      }
204
205      if (dimensionTrackbars.Any())
206        dimensionTrackbars.First().Checked = true;
207
208      tableLayoutPanel.ResumeLayout(true);
209      tableLayoutPanel.ResumeRepaint(true);
210    }
211
212    private void RegisterEvents(DensityTrackbar trackbar) {
213      trackbar.CheckedChanged += DimensionTrackbar_CheckedChanged;
214      trackbar.ValueChanged += DimensionTrackbar_ValueChanged;
215      trackbar.LimitsChanged += DimensionTrackbar_LimitsChanged;
216    }
217
218    private void DeregisterEvents(DensityTrackbar trackbar) {
219      trackbar.CheckedChanged -= DimensionTrackbar_CheckedChanged;
220      trackbar.ValueChanged -= DimensionTrackbar_ValueChanged;
221      trackbar.LimitsChanged -= DimensionTrackbar_LimitsChanged;
222    }
223
224    private void DimensionTrackbar_CheckedChanged(object sender, EventArgs e) {
225      var trackBarSender = sender as DensityTrackbar;
226      if (trackBarSender == null || !trackBarSender.Checked) return;
227      // Uncheck all others
228      foreach (var tb in dimensionTrackbars.Except(new[] { trackBarSender }))
229        tb.Checked = false;
230      RedrawChart();
231    }
232
233    private void DimensionTrackbar_LimitsChanged(object sender, EventArgs e) {
234      RedrawChart();
235    }
236
237    private void DimensionTrackbar_ValueChanged(object sender, EventArgs e) {
238      RedrawChart();
239    }
240
241    #region Events
242
243    protected override void RegisterContentEvents() {
244      base.RegisterContentEvents();
245      Content.ModelChanged += Content_ModelChanged;
246      Content.ProblemDataChanged += Content_ProblemDataChanged;
247    }
248
249    protected override void DeregisterContentEvents() {
250      base.DeregisterContentEvents();
251      Content.ModelChanged -= Content_ModelChanged;
252      Content.ProblemDataChanged -= Content_ProblemDataChanged;
253    }
254
255    protected override void OnContentChanged() {
256      base.OnContentChanged();
257      UpdateConfigurationControls();
258      RedrawChart();
259    }
260
261    private void Content_ModelChanged(object sender, EventArgs e) {
262      RedrawChart();
263    }
264
265    private void Content_ProblemDataChanged(object sender, EventArgs e) {
266      UpdateConfigurationControls();
267      RedrawChart();
268    }
269
270    private void Chart_MouseDoubleClick(object sender, MouseEventArgs e) {
271      var result = chart.HitTest(e.X, e.Y);
272      if (true || result.ChartArea != null && (result.ChartElementType == ChartElementType.PlottingArea ||
273                                               result.ChartElementType == ChartElementType.Gridlines) ||
274          result.ChartElementType == ChartElementType.StripLines) {
275        foreach (var axis in result.ChartArea.Axes)
276          axis.ScaleView.ZoomReset(int.MaxValue);
277      }
278    }
279
280    private void chart_MouseMove(object sender, MouseEventArgs e) {
281      //HitTestResult result = chart.HitTest(e.X, e.Y);
282      //if (result.ChartElementType == ChartElementType.LegendItem && result.Series.Name != TARGETVARIABLE_SERIES_NAME)
283      //  Cursor = Cursors.Hand;
284      //else
285      //  Cursor = Cursors.Default;
286    }
287
288    private void chart_MouseDown(object sender, MouseEventArgs e) {
289      //HitTestResult result = chart.HitTest(e.X, e.Y);
290      //if (result.ChartElementType == ChartElementType.LegendItem && result.Series.Name != TARGETVARIABLE_SERIES_NAME) {
291      //  ToggleSeriesData(result.Series);
292      //}
293    }
294
295    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
296      //if (chart.Series.Count != 4) return;
297      //e.LegendItems[0].Cells[1].ForeColor = this.chart.Series[EstimatedMeanSeriesName].Points.Count == 0 ? Color.Gray : Color.Black;
298      //e.LegendItems[1].Cells[1].ForeColor = this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
299      //e.LegendItems[2].Cells[1].ForeColor = this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
300      //e.LegendItems[3].Cells[1].ForeColor = this.chart.Series[TARGETVARIABLE_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
301    }
302
303    #endregion
304
305    #region Helper
306
307    private double GetLowerConfBound(double m, double s2) {
308      return m - 1.96 * Math.Sqrt(s2);
309    }
310
311    private double GetUpperConfBound(double m, double s2) {
312      return m + 1.96 * Math.Sqrt(s2);
313    }
314
315    public static void ForEach<T>(IEnumerable<T> source, Action<T> action) {
316      foreach (T item in source)
317        action(item);
318    }
319
320    #endregion
321  }
322}
Note: See TracBrowser for help on using the repository browser.