Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/GaussianProcessRegressionSolutionIteractiveRangeEstimatorView.cs @ 13812

Last change on this file since 13812 was 13812, checked in by pfleck, 8 years ago

#2597: Added an new View for GaussianProcessSolutions to be able to interactively show the gradients and confidence intervals for user-input ranges.

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