Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Views/3.4/TimeSeriesPrognosis/TimeSeriesPrognosisSolutionLineChartView.cs @ 7989

Last change on this file since 7989 was 7989, checked in by mkommend, 12 years ago

#1081: Improved performance of time series prognosis.

File size: 13.4 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2011 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
21using System;
22using System.Collections.Generic;
23using System.Drawing;
24using System.Linq;
25using System.Windows.Forms;
26using System.Windows.Forms.DataVisualization.Charting;
27using HeuristicLab.MainForm;
28using HeuristicLab.MainForm.WindowsForms;
29
30namespace HeuristicLab.Problems.DataAnalysis.Views {
31  [View("Line Chart")]
32  [Content(typeof(ITimeSeriesPrognosisSolution))]
33  public partial class TimeSeriesPrognosisSolutionLineChartView : DataAnalysisSolutionEvaluationView {
34    private const string TARGETVARIABLE_SERIES_NAME = "Target Variable";
35    private const string PROGNOSEDVALUES_TRAINING_SERIES_NAME = "Prognosed Values (training)";
36    private const string PROGNOSEDVALUES_TEST_SERIES_NAME = "Prognosed Values (test)";
37    private const string PROGNOSEDVALUES_ALL_SERIES_NAME = "Prognosed Values (all samples)";
38    private int testPrognosisStart;
39
40    public new ITimeSeriesPrognosisSolution Content {
41      get { return (ITimeSeriesPrognosisSolution)base.Content; }
42      set { base.Content = value; }
43    }
44
45    public TimeSeriesPrognosisSolutionLineChartView()
46      : base() {
47      InitializeComponent();
48      //configure axis
49      this.chart.CustomizeAllChartAreas();
50      this.chart.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
51      this.chart.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
52      this.chart.ChartAreas[0].AxisX.IsStartedFromZero = true;
53      this.chart.ChartAreas[0].CursorX.Interval = 1;
54
55      this.chart.ChartAreas[0].CursorY.IsUserSelectionEnabled = true;
56      this.chart.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
57      this.chart.ChartAreas[0].CursorY.Interval = 0;
58    }
59
60    private void RedrawChart() {
61      this.chart.Series.Clear();
62      if (Content != null) {
63        this.chart.ChartAreas[0].AxisX.Minimum = 0;
64        this.chart.ChartAreas[0].AxisX.Maximum = Content.ProblemData.Dataset.Rows - 1;
65        string targetVariable = Content.ProblemData.TargetVariable;
66
67        this.chart.Series.Add(TARGETVARIABLE_SERIES_NAME);
68        this.chart.Series[TARGETVARIABLE_SERIES_NAME].LegendText = targetVariable;
69        this.chart.Series[TARGETVARIABLE_SERIES_NAME].ChartType = SeriesChartType.FastLine;
70        this.chart.Series[TARGETVARIABLE_SERIES_NAME].Points.DataBindXY(Enumerable.Range(0, Content.ProblemData.Dataset.Rows).ToArray(),
71          Content.ProblemData.Dataset.GetDoubleValues(targetVariable).ToArray());
72
73        this.chart.Series.Add(PROGNOSEDVALUES_TRAINING_SERIES_NAME);
74        this.chart.Series[PROGNOSEDVALUES_TRAINING_SERIES_NAME].LegendText = PROGNOSEDVALUES_TRAINING_SERIES_NAME;
75        this.chart.Series[PROGNOSEDVALUES_TRAINING_SERIES_NAME].ChartType = SeriesChartType.FastLine;
76        if (prognosedValuesCheckbox.Checked) {
77          this.chart.Series[PROGNOSEDVALUES_TRAINING_SERIES_NAME].Points
78            .DataBindXY(Content.ProblemData.TrainingIndizes.ToArray(),
79                        Content.GetPrognosedValues(Content.ProblemData.TrainingIndizes.Take(1), Content.ProblemData.TrainingPartition.Size).SelectMany(x => x).ToArray());
80        } else {
81          this.chart.Series[PROGNOSEDVALUES_TRAINING_SERIES_NAME].Points
82            .DataBindXY(Content.ProblemData.TrainingIndizes.ToArray(),
83                        Content.GetPrognosedValues(Content.ProblemData.TrainingIndizes, 1).SelectMany(x => x).ToArray());
84        }
85        this.chart.Series[PROGNOSEDVALUES_TRAINING_SERIES_NAME].Tag = Content;
86        this.chart.DataManipulator.InsertEmptyPoints(1, IntervalType.Number, PROGNOSEDVALUES_TRAINING_SERIES_NAME);
87        this.chart.Series[PROGNOSEDVALUES_TRAINING_SERIES_NAME].EmptyPointStyle.BorderWidth = 0;
88        this.chart.Series[PROGNOSEDVALUES_TRAINING_SERIES_NAME].EmptyPointStyle.MarkerStyle = MarkerStyle.None;
89
90
91        this.chart.Series.Add(PROGNOSEDVALUES_TEST_SERIES_NAME);
92        this.chart.Series[PROGNOSEDVALUES_TEST_SERIES_NAME].LegendText = PROGNOSEDVALUES_TEST_SERIES_NAME;
93        this.chart.Series[PROGNOSEDVALUES_TEST_SERIES_NAME].ChartType = SeriesChartType.FastLine;
94        if (prognosedValuesCheckbox.Checked) {
95          this.chart.Series[PROGNOSEDVALUES_TEST_SERIES_NAME].Points
96            .DataBindXY(Content.ProblemData.TestIndizes.ToArray(),
97                        Content.GetPrognosedValues(Content.ProblemData.TestIndizes.Take(1), Content.ProblemData.TestPartition.Size).SelectMany(x => x).ToArray());
98        } else {
99          this.chart.Series[PROGNOSEDVALUES_TEST_SERIES_NAME].Points
100            .DataBindXY(Content.ProblemData.TestIndizes.ToArray(),
101                        Content.GetPrognosedValues(Content.ProblemData.TestIndizes, 1).SelectMany(x => x).ToArray());
102        }
103        this.chart.Series[PROGNOSEDVALUES_TEST_SERIES_NAME].Tag = Content;
104
105        UpdateCursorInterval();
106        this.UpdateStripLines();
107      }
108    }
109
110    private void UpdateCursorInterval() {
111      var estimatedValues = this.chart.Series[PROGNOSEDVALUES_TRAINING_SERIES_NAME].Points.Select(x => x.YValues[0]).DefaultIfEmpty(1.0);
112      var targetValues = this.chart.Series[TARGETVARIABLE_SERIES_NAME].Points.Select(x => x.YValues[0]).DefaultIfEmpty(1.0);
113      double estimatedValuesRange = estimatedValues.Max() - estimatedValues.Min();
114      double targetValuesRange = targetValues.Max() - targetValues.Min();
115      double interestingValuesRange = Math.Min(Math.Max(targetValuesRange, 1.0), Math.Max(estimatedValuesRange, 1.0));
116      double digits = (int)Math.Log10(interestingValuesRange) - 3;
117      double yZoomInterval = Math.Max(Math.Pow(10, digits), 10E-5);
118      this.chart.ChartAreas[0].CursorY.Interval = yZoomInterval;
119    }
120
121    #region events
122    protected override void RegisterContentEvents() {
123      base.RegisterContentEvents();
124      Content.ModelChanged += new EventHandler(Content_ModelChanged);
125      Content.ProblemDataChanged += new EventHandler(Content_ProblemDataChanged);
126    }
127    protected override void DeregisterContentEvents() {
128      base.DeregisterContentEvents();
129      Content.ModelChanged -= new EventHandler(Content_ModelChanged);
130      Content.ProblemDataChanged -= new EventHandler(Content_ProblemDataChanged);
131    }
132
133    protected override void OnContentChanged() {
134      base.OnContentChanged();
135      RedrawChart();
136    }
137
138    private void Content_ProblemDataChanged(object sender, EventArgs e) {
139      RedrawChart();
140    }
141    private void Content_ModelChanged(object sender, EventArgs e) {
142      RedrawChart();
143    }
144
145    private void targetVariableComboBox_SelectedIndexChanged(object sender, EventArgs e) {
146      RedrawChart();
147    }
148    private void prognosedValuesCheckbox_CheckedChanged(object sender, EventArgs e) {
149      RedrawChart();
150    }
151
152    private void Chart_MouseDoubleClick(object sender, MouseEventArgs e) {
153      HitTestResult result = chart.HitTest(e.X, e.Y);
154      if (result.ChartArea != null && (result.ChartElementType == ChartElementType.PlottingArea ||
155                                       result.ChartElementType == ChartElementType.Gridlines) ||
156                                       result.ChartElementType == ChartElementType.StripLines) {
157        foreach (var axis in result.ChartArea.Axes)
158          axis.ScaleView.ZoomReset(int.MaxValue);
159      }
160    }
161    #endregion
162
163    private void UpdateStripLines() {
164      this.chart.ChartAreas[0].AxisX.StripLines.Clear();
165
166      int[] attr = new int[Content.ProblemData.Dataset.Rows + 1]; // add a virtual last row that is again empty to simplify loop further down
167      foreach (var row in Content.ProblemData.TrainingIndizes) {
168        attr[row] += 1;
169      }
170      foreach (var row in Content.ProblemData.TestIndizes) {
171        attr[row] += 2;
172      }
173      int start = 0;
174      int curAttr = attr[start];
175      for (int row = 0; row < attr.Length; row++) {
176        if (attr[row] != curAttr) {
177          switch (curAttr) {
178            case 0: break;
179            case 1:
180              this.CreateAndAddStripLine("Training", start, row, Color.FromArgb(40, Color.Green), Color.Transparent);
181              break;
182            case 2:
183              this.CreateAndAddStripLine("Test", start, row, Color.FromArgb(40, Color.Red), Color.Transparent);
184              break;
185            case 3:
186              this.CreateAndAddStripLine("Training and Test", start, row, Color.FromArgb(40, Color.Green), Color.FromArgb(40, Color.Red), ChartHatchStyle.WideUpwardDiagonal);
187              break;
188            default: throw new NotSupportedException();
189          }
190          curAttr = attr[row];
191          start = row;
192        }
193      }
194    }
195
196    private void CreateAndAddStripLine(string title, int start, int end, Color color, Color secondColor, ChartHatchStyle hatchStyle = ChartHatchStyle.None) {
197      StripLine stripLine = new StripLine();
198      stripLine.BackColor = color;
199      stripLine.BackSecondaryColor = secondColor;
200      stripLine.BackHatchStyle = hatchStyle;
201      stripLine.Text = title;
202      stripLine.Font = new Font("Times New Roman", 12, FontStyle.Bold);
203      // strip range is [start .. end] inclusive, but we evaluate [start..end[ (end is exclusive)
204      // the strip should be by one longer (starting at start - 0.5 and ending at end + 0.5)
205      stripLine.StripWidth = end - start;
206      stripLine.IntervalOffset = start - 0.5; // start slightly to the left of the first point to clearly indicate the first point in the partition
207      this.chart.ChartAreas[0].AxisX.StripLines.Add(stripLine);
208    }
209
210    private void ToggleSeriesData(Series series) {
211      if (series.Points.Count > 0) {  //checks if series is shown
212        if (this.chart.Series.Any(s => s != series && s.Points.Count > 0)) {
213          series.Points.Clear();
214        }
215      } else if (Content != null) {
216        string targetVariable = Content.ProblemData.TargetVariable;
217
218        IEnumerable<int> indizes = null;
219        IEnumerable<double> predictedValues = null;
220
221        switch (series.Name) {
222          case PROGNOSEDVALUES_TRAINING_SERIES_NAME:
223            indizes = Content.ProblemData.TrainingIndizes.ToArray();
224            predictedValues = Content.GetPrognosedValues(Content.ProblemData.TrainingIndizes.Take(1), Content.ProblemData.TrainingPartition.Size).First();
225            break;
226          case PROGNOSEDVALUES_TEST_SERIES_NAME:
227            testPrognosisStart = Content.ProblemData.TestPartition.Start;
228            indizes = Content.ProblemData.TestIndizes.ToArray();
229            predictedValues = Content.GetPrognosedValues(Content.ProblemData.TestIndizes.Take(1), Content.ProblemData.TestPartition.Size).First();
230            break;
231        }
232        series.Points.DataBindXY(indizes, predictedValues);
233        chart.DataManipulator.InsertEmptyPoints(1, IntervalType.Number, series.Name);
234        chart.Legends[series.Legend].ForeColor = Color.Black;
235        UpdateCursorInterval();
236        chart.Refresh();
237      }
238    }
239
240    private void chart_MouseMove(object sender, MouseEventArgs e) {
241      HitTestResult result = chart.HitTest(e.X, e.Y);
242      if (result.ChartElementType == ChartElementType.LegendItem && result.Series.Name != TARGETVARIABLE_SERIES_NAME)
243        Cursor = Cursors.Hand;
244      else
245        Cursor = Cursors.Default;
246    }
247
248    private void chart_MouseDown(object sender, MouseEventArgs e) {
249      HitTestResult result = chart.HitTest(e.X, e.Y);
250      if (result.ChartElementType == ChartElementType.LegendItem && result.Series.Name != TARGETVARIABLE_SERIES_NAME) {
251        ToggleSeriesData(result.Series);
252      } else if (result.ChartElementType == ChartElementType.Axis || result.ChartElementType == ChartElementType.AxisLabels ||
253        result.ChartElementType == ChartElementType.TickMarks) {
254        chart.ChartAreas[0].CursorX.SetCursorPixelPosition(new Point(e.X, e.Y), true);
255        int pos = (int)Math.Round(chart.ChartAreas[0].CursorX.Position);
256        if (pos >= Content.ProblemData.TestPartition.Start && pos < Content.ProblemData.TestPartition.End) {
257          testPrognosisStart = pos;
258          RedrawChart();
259        }
260      }
261    }
262
263    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
264      if (chart.Series.Count != 4) return;
265      e.LegendItems[0].Cells[1].ForeColor = this.chart.Series[TARGETVARIABLE_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
266      e.LegendItems[1].Cells[1].ForeColor = this.chart.Series[PROGNOSEDVALUES_TRAINING_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
267      e.LegendItems[2].Cells[1].ForeColor = this.chart.Series[PROGNOSEDVALUES_TEST_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
268      e.LegendItems[3].Cells[1].ForeColor = this.chart.Series[PROGNOSEDVALUES_ALL_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
269    }
270  }
271}
Note: See TracBrowser for help on using the repository browser.