Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionParameterAnalysisView.cs @ 14640

Last change on this file since 14640 was 14640, checked in by swagner, 7 years ago

#2726: Fixed fail of ContentViewAttributeTest

File size: 24.6 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.ComponentModel;
25using System.Data;
26using System.Linq;
27using System.Windows.Forms;
28using HeuristicLab.Analysis;
29using HeuristicLab.Collections;
30using HeuristicLab.Common;
31using HeuristicLab.Core.Views;
32using HeuristicLab.MainForm;
33using System.Windows.Forms.DataVisualization.Charting;
34using System.Text;
35using HeuristicLab.Data;
36using System.Drawing;
37using HeuristicLab.Core;
38
39namespace HeuristicLab.Optimization.Views {
40  [View("Parameter Analysis")]
41  [Content(typeof(RunCollection), false)]
42  public sealed partial class RunCollectionParameterAnalysisView : ItemView {
43    #region Colors
44    private static readonly Color[] colors = new[] {
45      Color.FromArgb(0x40, 0x6A, 0xB7),
46      Color.FromArgb(0xB1, 0x6D, 0x01),
47      Color.FromArgb(0x4E, 0x8A, 0x06),
48      Color.FromArgb(0x75, 0x50, 0x7B),
49      Color.FromArgb(0x72, 0x9F, 0xCF),
50      Color.FromArgb(0xA4, 0x00, 0x00),
51      Color.FromArgb(0xAD, 0x7F, 0xA8),
52      Color.FromArgb(0x29, 0x50, 0xCF),
53      Color.FromArgb(0x90, 0xB0, 0x60),
54      Color.FromArgb(0xF5, 0x89, 0x30),
55      Color.FromArgb(0x55, 0x57, 0x53),
56      Color.FromArgb(0xEF, 0x59, 0x59),
57      Color.FromArgb(0xED, 0xD4, 0x30),
58      Color.FromArgb(0x63, 0xC2, 0x16),
59    };
60    #endregion
61
62    private bool suppressUpdates = false;
63    private int stepSize = 1000;
64    private Dictionary<IRun, List<Tuple<int, double>>> runData;
65    private Dictionary<string, ParameterInfo> paramInfos;
66
67    public new RunCollection Content {
68      get { return (RunCollection)base.Content; }
69      set { base.Content = value; }
70    }
71
72    public RunCollectionParameterAnalysisView() {
73      InitializeComponent();
74      chart.CustomizeAllChartAreas();
75      stepSizeTextBox.Text = stepSize.ToString();
76      errorProvider.SetIconAlignment(stepSizeTextBox, ErrorIconAlignment.MiddleLeft);
77      errorProvider.SetIconPadding(stepSizeTextBox, 2);
78    }
79
80    #region Content Events
81    protected override void DeregisterContentEvents() {
82      Content.ItemsAdded -= Content_ItemsAdded;
83      Content.ItemsRemoved -= Content_ItemsRemoved;
84      Content.CollectionReset -= Content_CollectionReset;
85      Content.UpdateOfRunsInProgressChanged -= Content_UpdateOfRunsInProgressChanged;
86      DeregisterRunEvents(Content);
87      base.DeregisterContentEvents();
88    }
89    protected override void RegisterContentEvents() {
90      base.RegisterContentEvents();
91      Content.ItemsAdded += Content_ItemsAdded;
92      Content.ItemsRemoved += Content_ItemsRemoved;
93      Content.CollectionReset += Content_CollectionReset;
94      Content.UpdateOfRunsInProgressChanged += Content_UpdateOfRunsInProgressChanged;
95      RegisterRunEvents(Content);
96    }
97    private void DeregisterRunEvents(IEnumerable<IRun> runs) {
98      foreach (var run in runs)
99        run.PropertyChanged -= Run_PropertyChanged;
100    }
101    private void RegisterRunEvents(IEnumerable<IRun> runs) {
102      foreach (var run in runs)
103        run.PropertyChanged += Run_PropertyChanged;
104    }
105
106    private void Content_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRun> e) {
107      RegisterRunEvents(e.Items);
108    }
109    private void Content_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRun> e) {
110      DeregisterRunEvents(e.Items);
111    }
112    private void Content_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
113      DeregisterRunEvents(e.OldItems);
114      RegisterRunEvents(e.Items);
115    }
116    private void Content_UpdateOfRunsInProgressChanged(object sender, EventArgs e) {
117      if (InvokeRequired)
118        Invoke((Action<object, EventArgs>)Content_UpdateOfRunsInProgressChanged, sender, e);
119      else {
120        suppressUpdates = Content.UpdateOfRunsInProgress;
121        if (suppressUpdates) return;
122        CollectRunData();
123        AnalyzeParameters();
124        UpdateChart();
125      }
126    }
127    private void Run_PropertyChanged(object sender, PropertyChangedEventArgs e) {
128      if (suppressUpdates) return;
129      if (InvokeRequired)
130        Invoke((Action<object, PropertyChangedEventArgs>)Run_PropertyChanged, sender, e);
131      else {
132        CollectRunData();
133        AnalyzeParameters();
134        UpdateChart();
135      }
136    }
137    #endregion
138
139    protected override void OnContentChanged() {
140      base.OnContentChanged();
141      CollectRunData();
142      AnalyzeParameters();
143      UpdateChart();
144    }
145    protected override void SetEnabledStateOfControls() {
146      base.SetEnabledStateOfControls();
147      parametersGroupBox.Enabled = Content != null;
148      groupsGroupBox.Enabled = Content != null;
149      stepSizeTextBox.Enabled = Content != null;
150      logScalingCheckBox.Enabled = Content != null;
151      dataRowsGroupBox.Enabled = Content != null;
152    }
153
154    private void AnalyzeParameters() {
155      paramInfos = new Dictionary<string, ParameterInfo>();
156      if (Content == null) return;
157
158      foreach (var run in runData.Keys) {
159        foreach (var param in run.Parameters) {
160          ParameterInfo info;
161          if (!paramInfos.TryGetValue(param.Key, out info))
162            paramInfos.Add(param.Key, new ParameterInfo(param.Key, param.Value.ToString(), run));
163          else
164            info.AddValue(param.Value.ToString(), run);
165        }
166      }
167
168      // remove irrelevant parameters
169      if (paramInfos.ContainsKey("Seed"))
170        paramInfos.Remove("Seed");
171
172      // remove all parameters which only have a single value
173      var singles = new List<string>();
174      foreach (var paramInfo in paramInfos.Values) {
175        if (paramInfo.Values.Count == 1)
176          singles.Add(paramInfo.Name);
177      }
178      foreach (var single in singles)
179        paramInfos.Remove(single);
180
181      // set color of parameter values
182      int i = 0;
183      foreach (var valueInfo in paramInfos.Values.SelectMany(x => x.Values.Values)) {
184        valueInfo.Color = colors[i];
185        i = (i + 1) % colors.Length;
186      }
187
188      // populate parametersTreeView
189      parametersTreeView.Nodes.Clear();
190      var paramsRoot = new TreeNode("All Runs (" + runData.Keys.Count + ")");
191      paramsRoot.Tag = runData.Keys.ToList();
192      foreach (var paramInfo in paramInfos.Values.OrderBy(x => x.Name)) {
193        var node = new TreeNode(paramInfo.Name + " (" + paramInfo.RunCount + ")");
194        foreach (var value in paramInfo.Values) {
195          var child = new TreeNode(value.Key + " (" + value.Value.RunCount + ")");
196          child.Tag = value.Value;
197          node.Nodes.Add(child);
198        }
199        node.Tag = paramInfo;
200        paramsRoot.Nodes.Add(node);
201      }
202      parametersTreeView.Nodes.Add(paramsRoot);
203      paramsRoot.Expand();
204      parametersTreeView.SelectedNode = paramsRoot;
205
206      // populate groupsTreeView
207      groupsTreeView.Nodes.Clear();
208      var groupsRoot = new TreeNode("All Runs (" + runData.Keys.Count + ")");
209      groupsRoot.Tag = runData.Keys.ToList();
210      groupsTreeView.Nodes.Add(groupsRoot);
211      groupsRoot.Expand();
212      groupsTreeView.SelectedNode = groupsRoot;
213    }
214    private void CollectRunData() {
215      runData = new Dictionary<IRun, List<Tuple<int, double>>>();
216      if (Content == null) return;
217
218      foreach (var run in Content) {
219        try {
220          IList<Tuple<double, double>> values = (run.Results["QualityPerEvaluations"] as IndexedDataTable<double>).Rows["First-hit Graph"].Values;
221          var bestKnown = (run.Results["BestKnownQuality"] as DoubleValue).Value;
222
223          var data = new List<Tuple<int, double>>();
224          int i = 0;
225          double qual = double.NaN;
226          foreach (var val in values) {
227            while (i * stepSize < val.Item1) {
228              if (!double.IsNaN(qual)) data.Add(Tuple.Create(i * stepSize, qual));
229              i++;
230            }
231            var diff = Math.Abs(bestKnown - val.Item2);
232            qual = bestKnown == 0 ? diff : diff / bestKnown;
233          }
234          runData.Add(run, data);
235        }
236        catch {
237        }
238      }
239    }
240
241    private void UpdateChart() {
242      if (suppressUpdates) return;
243
244      chart.Series.Clear();
245      chart.Legends[0].CustomItems.Clear();
246      var selectedNode = groupsTreeView.Focused ? groupsTreeView.SelectedNode : parametersTreeView.SelectedNode;
247      if (selectedNode == null) return;
248      if (selectedNode.Parent == null) {
249        var series = BuildSeries(selectedNode.Tag as IEnumerable<IRun>, colors[0]);
250        chart.Titles[0].Text = selectedNode.Text;
251        foreach (var s in series)
252          chart.Series.Add(s);
253        var legendItem = new LegendItem();
254        var legendItemInfo = new LegendItemInfo(colors[0], series);
255        legendItem.Color = legendItemInfo.Color;
256        legendItem.BorderColor = Color.Transparent;
257        legendItem.Name = selectedNode.Text;
258        legendItem.Tag = legendItemInfo;
259        chart.Legends[0].CustomItems.Add(legendItem);
260      } else if (selectedNode.Tag is ParameterInfo) {
261        var paramInfo = selectedNode.Tag as ParameterInfo;
262        chart.Titles[0].Text = paramInfo.Name + " (" + paramInfo.RunCount + ")";
263        foreach (var value in paramInfo.Values) {
264          var series = BuildSeries(value.Value.Runs, value.Value.Color);
265          foreach (var s in series)
266            chart.Series.Add(s);
267          var legendItem = new LegendItem();
268          var legendItemInfo = new LegendItemInfo(value.Value.Color, series);
269          legendItem.Color = legendItemInfo.Color;
270          legendItem.BorderColor = Color.Transparent;
271          legendItem.Name = value.Key + " (" + value.Value.RunCount + ")";
272          legendItem.Tag = legendItemInfo;
273          chart.Legends[0].CustomItems.Add(legendItem);
274        }
275      } else if (selectedNode.Tag is ParameterValueInfo) {
276        var valueInfo = selectedNode.Tag as ParameterValueInfo;
277        var series = BuildSeries(valueInfo.Runs, valueInfo.Color);
278        chart.Titles[0].Text = selectedNode.Parent.Text;
279        foreach (var s in series)
280          chart.Series.Add(s);
281        var legendItem = new LegendItem();
282        var legendItemInfo = new LegendItemInfo(valueInfo.Color, series);
283        legendItem.Color = legendItemInfo.Color;
284        legendItem.BorderColor = Color.Transparent;
285        legendItem.Name = selectedNode.Text;
286        legendItem.Tag = legendItemInfo;
287        chart.Legends[0].CustomItems.Add(legendItem);
288      } else if (selectedNode.Tag is GroupInfo) {
289        var groupInfo = selectedNode.Tag as GroupInfo;
290        if (groupInfo.IsParameter) {
291          chart.Titles[0].Text = groupInfo.Text + " (" + groupInfo.Runs.Count + ")";
292          foreach (TreeNode node in selectedNode.Nodes) {
293            var childInfo = node.Tag as GroupInfo;
294            var series = BuildSeries(childInfo.Runs, childInfo.Color);
295            foreach (var s in series)
296              chart.Series.Add(s);
297            var legendItem = new LegendItem();
298            var legendItemInfo = new LegendItemInfo(childInfo.Color, series);
299            legendItem.Color = legendItemInfo.Color;
300            legendItem.BorderColor = Color.Transparent;
301            legendItem.Name = childInfo.Text + " (" + childInfo.Runs.Count + ")";
302            legendItem.Tag = legendItemInfo;
303            chart.Legends[0].CustomItems.Add(legendItem);
304          }
305        } else {
306          var parentInfo = selectedNode.Parent.Tag as GroupInfo;
307          chart.Titles[0].Text = parentInfo.Text + " (" + parentInfo.Runs.Count + ")";
308          var series = BuildSeries(groupInfo.Runs, groupInfo.Color);
309          foreach (var s in series)
310            chart.Series.Add(s);
311          var legendItem = new LegendItem();
312          var legendItemInfo = new LegendItemInfo(groupInfo.Color, series);
313          legendItem.Color = legendItemInfo.Color;
314          legendItem.BorderColor = Color.Transparent;
315          legendItem.Name = groupInfo.Text + " (" + groupInfo.Runs.Count + ")";
316          legendItem.Tag = legendItemInfo;
317          chart.Legends[0].CustomItems.Add(legendItem);
318        }
319      }
320    }
321    private void UpdateSeriesVisibility() {
322      foreach (var legendItem in chart.Legends[0].CustomItems) {
323        var legendItemInfo = legendItem.Tag as LegendItemInfo;
324        foreach (var s in legendItemInfo.Series) {
325          if (legendItemInfo.SeriesVisible) {
326            var seriesInfo = s.Tag as SeriesInfo;
327            switch (seriesInfo.Type) {
328              case SeriesTypes.MinMax:
329                s.Color = minMaxCheckBox.Checked ? seriesInfo.Color : Color.Transparent;
330                break;
331              case SeriesTypes.Quartiles:
332                s.Color = quartilesCheckBox.Checked ? seriesInfo.Color : Color.Transparent;
333                break;
334              case SeriesTypes.Median:
335                s.Color = medianCheckBox.Checked ? seriesInfo.Color : Color.Transparent;
336                break;
337              case SeriesTypes.Average:
338                s.Color = averageCheckBox.Checked ? seriesInfo.Color : Color.Transparent;
339                break;
340            }
341          } else {
342            s.Color = Color.Transparent;
343          }
344        }
345      }
346    }
347
348    private IEnumerable<Series> BuildSeries(IEnumerable<IRun> runs, Color color) {
349      var values = new Dictionary<int, List<double>>();
350      foreach (var run in runs) {
351        foreach (var step in runData[run]) {
352          List<double> vals;
353          if (!values.TryGetValue(step.Item1, out vals)) {
354            vals = new List<double>();
355            values.Add(step.Item1, vals);
356          }
357          vals.Add(step.Item2);
358        }
359      }
360
361      List<Series> series = new List<Series>();
362      var minMaxSeries = new Series();
363      var minMaxSeriesInfo = new SeriesInfo(Color.FromArgb(25, color), SeriesTypes.MinMax);
364      minMaxSeries.ChartType = SeriesChartType.Range;
365      minMaxSeries.Color = minMaxCheckBox.Checked ? minMaxSeriesInfo.Color : Color.Transparent;
366      minMaxSeries.IsVisibleInLegend = false;
367      minMaxSeries.Tag = minMaxSeriesInfo;
368      series.Add(minMaxSeries);
369
370      var quartilesSeries = new Series();
371      var quartilesSeriesInfo = new SeriesInfo(Color.FromArgb(50, color), SeriesTypes.Quartiles);
372      quartilesSeries.ChartType = SeriesChartType.Range;
373      quartilesSeries.Color = quartilesCheckBox.Checked ? quartilesSeriesInfo.Color : Color.Transparent;
374      quartilesSeries.IsVisibleInLegend = false;
375      quartilesSeries.Tag = quartilesSeriesInfo;
376      series.Add(quartilesSeries);
377
378      var medianSeries = new Series();
379      var medianSeriesInfo = new SeriesInfo(color, SeriesTypes.Median);
380      medianSeries.ChartType = SeriesChartType.FastLine;
381      medianSeries.Color = medianCheckBox.Checked ? medianSeriesInfo.Color : Color.Transparent;
382      medianSeries.BorderWidth = 3;
383      medianSeries.BorderDashStyle = ChartDashStyle.Solid;
384      medianSeries.IsVisibleInLegend = false;
385      medianSeries.Tag = medianSeriesInfo;
386      series.Add(medianSeries);
387
388      var averageSeries = new Series();
389      var averageSeriesInfo = new SeriesInfo(color, SeriesTypes.Average);
390      averageSeries.ChartType = SeriesChartType.FastLine;
391      averageSeries.Color = averageCheckBox.Checked ? averageSeriesInfo.Color : Color.Transparent;
392      averageSeries.BorderWidth = 3;
393      averageSeries.BorderDashStyle = ChartDashStyle.Dash;
394      averageSeries.IsVisibleInLegend = false;
395      averageSeries.Tag = averageSeriesInfo;
396      series.Add(averageSeries);
397
398      foreach (var point in values.OrderBy(x => x.Key)) {
399        if (point.Value.Count > 0) {
400          minMaxSeries.Points.Add(new DataPoint(point.Key, new double[] { point.Value.Min(), point.Value.Max() }));
401          quartilesSeries.Points.Add(new DataPoint(point.Key, new double[] { point.Value.Quantile(0.25), point.Value.Quantile(0.75) }));
402          medianSeries.Points.Add(new DataPoint(point.Key, point.Value.Median()));
403          averageSeries.Points.Add(new DataPoint(point.Key, point.Value.Average()));
404        }
405      }
406      return series;
407    }
408
409    #region Control Events
410    #region stepSizeTextBox
411    private void stepSizeTextBox_KeyDown(object sender, KeyEventArgs e) {
412      if ((e.KeyCode == Keys.Enter) || (e.KeyCode == Keys.Return))
413        stepSizeLabel.Select();  // select label to validate data
414
415      if (e.KeyCode == Keys.Escape) {
416        stepSizeTextBox.Text = stepSize.ToString();
417        stepSizeLabel.Select();  // select label to validate data
418      }
419    }
420    private void stepSizeTextBox_Validating(object sender, CancelEventArgs e) {
421      int val;
422      if (!int.TryParse(stepSizeTextBox.Text, out val) || val <= 0) {
423        e.Cancel = true;
424        errorProvider.SetError(stepSizeTextBox, "Invalid Value (Valid Value Format: \"[+]digits\")");
425        stepSizeTextBox.SelectAll();
426      }
427    }
428    private void stepSizeTextBox_Validated(object sender, EventArgs e) {
429      int val = int.Parse(stepSizeTextBox.Text);
430      errorProvider.SetError(stepSizeTextBox, string.Empty);
431      stepSizeTextBox.Text = val.ToString();
432      if (stepSize != val) {
433        stepSize = val;
434        CollectRunData();
435        UpdateChart();
436      }
437    }
438    #endregion
439    #region logScalingCheckBox
440    private void logScalingCheckBox_CheckedChanged(object sender, EventArgs e) {
441      chart.ChartAreas[0].AxisX.IsLogarithmic = logScalingCheckBox.Checked;
442    }
443    #endregion
444    #region chart
445    private void chart_MouseDown(object sender, MouseEventArgs e) {
446      HitTestResult result = chart.HitTest(e.X, e.Y);
447      if (result.ChartElementType == ChartElementType.LegendItem) {
448        var legendItemInfo = (result.Object as LegendItem).Tag as LegendItemInfo;
449        legendItemInfo.SeriesVisible = !legendItemInfo.SeriesVisible;
450        UpdateSeriesVisibility();
451      }
452    }
453    private void chart_MouseMove(object sender, MouseEventArgs e) {
454      HitTestResult result = chart.HitTest(e.X, e.Y);
455      switch (result.ChartElementType) {
456        case ChartElementType.LegendItem:
457          Cursor = Cursors.Hand;
458          break;
459        default:
460          Cursor = Cursors.Default;
461          break;
462      }
463    }
464    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
465      foreach (LegendItem legendItem in e.LegendItems) {
466        var legendItemInfo = legendItem.Tag as LegendItemInfo;
467        legendItem.Color = legendItemInfo.SeriesVisible ? legendItemInfo.Color : Color.Transparent;
468        foreach (LegendCell cell in legendItem.Cells) {
469          cell.ForeColor = legendItemInfo.SeriesVisible ? Color.Black : Color.Gray;
470        }
471      }
472    }
473    #endregion
474    #region parametersTreeView
475    private void parametersTreeView_AfterSelect(object sender, TreeViewEventArgs e) {
476      UpdateChart();
477      addGroupButton.Enabled = (parametersTreeView.SelectedNode != null) && (parametersTreeView.SelectedNode.Parent != null);
478    }
479    #endregion
480    #region groupsTreeView
481    private void groupsTreeView_AfterSelect(object sender, TreeViewEventArgs e) {
482      UpdateChart();
483      removeGroupButton.Enabled = (groupsTreeView.SelectedNode != null) && (groupsTreeView.SelectedNode.Parent != null);
484    }
485    #endregion
486    #region addGroupButton, removeGroupButton
487    private void addGroupButton_Click(object sender, EventArgs e) {
488      var group = groupsTreeView.SelectedNode;
489      var param = parametersTreeView.SelectedNode;
490      var groupRuns = group.Parent == null ? group.Tag as IEnumerable<IRun> : (group.Tag as GroupInfo).Runs;
491
492      if (param.Tag is ParameterInfo) {
493        var paramInfo = param.Tag as ParameterInfo;
494        var paramNode = new TreeNode();
495        int count = 0;
496        foreach (var valueInfo in paramInfo.Values.Values) {
497          var runs = groupRuns.Intersect(valueInfo.Runs);
498          var valueNode = new TreeNode(valueInfo.Value + " (" + runs.Count() + ")");
499          count += runs.Count();
500          valueNode.Tag = new GroupInfo(valueInfo.Value, valueInfo.Color, runs, false);
501          paramNode.Nodes.Add(valueNode);
502        }
503        paramNode.Text = paramInfo.Name + " (" + count + ")";
504        paramNode.Tag = new GroupInfo(paramInfo.Name, Color.Empty, paramInfo.Values.Values.SelectMany(x => x.Runs), true);
505        group.Nodes.Add(paramNode);
506      } else if (param.Tag is ParameterValueInfo) {
507        var paramInfo = param.Parent.Tag as ParameterInfo;
508        var valueInfo = param.Tag as ParameterValueInfo;
509        var runs = groupRuns.Intersect(valueInfo.Runs);
510        var paramNode = new TreeNode(paramInfo.Name + " (" + runs.Count() + ")");
511        var valueNode = new TreeNode(valueInfo.Value + " (" + runs.Count() + ")");
512        valueNode.Tag = new GroupInfo(valueInfo.Value, valueInfo.Color, runs, false);
513        paramNode.Tag = new GroupInfo(paramInfo.Name, Color.Empty, runs, true);
514        paramNode.Nodes.Add(valueNode);
515        group.Nodes.Add(paramNode);
516      }
517      groupsTreeView.Nodes[0].Expand();
518    }
519    private void removeGroupButton_Click(object sender, EventArgs e) {
520      if (groupsTreeView.SelectedNode != null)
521        groupsTreeView.SelectedNode.Remove();
522      UpdateChart();
523    }
524    #endregion
525    #region minMaxCheckBox, quartilesCheckBox, averageCheckBox, medianCheckBox
526    private void dataRowCheckBox_CheckedChanged(object sender, EventArgs e) {
527      UpdateSeriesVisibility();
528    }
529    #endregion
530    #endregion
531
532    #region Inner Types
533    class ParameterInfo {
534      public string Name { get; private set; }
535      public Dictionary<string, ParameterValueInfo> Values { get; private set; }
536      public IEnumerable<IRun> Runs {
537        get { return Values.Values.SelectMany(x => x.Runs); }
538      }
539      public int RunCount {
540        get { return Values.Values.Select(x => x.RunCount).Sum(); }
541      }
542
543      public ParameterInfo(string name, string value, IRun run) {
544        Name = name;
545        Values = new Dictionary<string, ParameterValueInfo>();
546        AddValue(value, run);
547      }
548      public void AddValue(string value, IRun run) {
549        ParameterValueInfo valueInfo;
550        if (!Values.TryGetValue(value, out valueInfo)) {
551          Values.Add(value, new ParameterValueInfo(value, run));
552        } else {
553          valueInfo.Runs.Add(run);
554        }
555      }
556    }
557    class ParameterValueInfo {
558      public string Value { get; private set; }
559      public Color Color { get; set; }
560      public IList<IRun> Runs { get; private set; }
561      public int RunCount {
562        get { return Runs.Count; }
563      }
564
565      public ParameterValueInfo(string value, IRun run) {
566        Value = value;
567        Runs = new List<IRun>();
568        Runs.Add(run);
569      }
570      public ParameterValueInfo(string value, Color color, IRun run) : this(value, run) {
571        Color = color;
572      }
573    }
574    class GroupInfo {
575      public string Text { get; private set; }
576      public Color Color { get; private set; }
577      public IList<IRun> Runs { get; private set; }
578      public bool IsParameter { get; private set; }
579      public GroupInfo(string text, Color color, IEnumerable<IRun> runs, bool isParamter) {
580        Text = text;
581        Color = color;
582        Runs = runs.ToList();
583        IsParameter = isParamter;
584      }
585    }
586    enum SeriesTypes {
587      MinMax,
588      Quartiles,
589      Average,
590      Median
591    }
592    class SeriesInfo {
593      public Color Color { get; private set; }
594      public SeriesTypes Type { get; private set; }
595      public SeriesInfo(Color color, SeriesTypes type) {
596        Color = color;
597        Type = type;
598      }
599    }
600    class LegendItemInfo {
601      public Color Color { get; private set; }
602      public bool SeriesVisible { get; set; }
603      public IEnumerable<Series> Series { get; private set; }
604      public LegendItemInfo(Color color, IEnumerable<Series> series) {
605        Color = color;
606        SeriesVisible = true;
607        Series = series;
608      }
609    }
610    #endregion
611  }
612}
Note: See TracBrowser for help on using the repository browser.