Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Optimization.Views/3.3/RunCollectionBubbleChartView.cs @ 4846

Last change on this file since 4846 was 4846, checked in by mkommend, 13 years ago

Readded lost context menu item in bubble chart (ticket #1281).

File size: 25.7 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 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.Common;
29using HeuristicLab.Core;
30using HeuristicLab.Data;
31using HeuristicLab.MainForm;
32using HeuristicLab.MainForm.WindowsForms;
33
34namespace HeuristicLab.Optimization.Views {
35  [View("RunCollection BubbleChart")]
36  [Content(typeof(RunCollection), false)]
37  public partial class RunCollectionBubbleChartView : AsynchronousContentView {
38    private enum SizeDimension { Constant = 0 }
39    private enum AxisDimension { Index = 0 }
40
41    private string xAxisValue;
42    private string yAxisValue;
43    private string sizeAxisValue;
44
45    private Dictionary<IRun, DataPoint> runToDataPointMapping;
46    private Dictionary<int, Dictionary<object, double>> categoricalMapping;
47    private Dictionary<IRun, double> xJitter;
48    private Dictionary<IRun, double> yJitter;
49    private double xJitterFactor = 0.0;
50    private double yJitterFactor = 0.0;
51    private Random random;
52    private bool isSelecting = false;
53
54    public RunCollectionBubbleChartView() {
55      InitializeComponent();
56      chart.ContextMenuStrip.Items.Insert(0, openBoxPlotViewToolStripMenuItem);
57
58      runToDataPointMapping = new Dictionary<IRun, DataPoint>();
59      categoricalMapping = new Dictionary<int, Dictionary<object, double>>();
60      xJitter = new Dictionary<IRun, double>();
61      yJitter = new Dictionary<IRun, double>();
62      random = new Random();
63
64      colorDialog.Color = Color.Black;
65      colorButton.Image = this.GenerateImage(16, 16, this.colorDialog.Color);
66      isSelecting = false;
67
68      chart.CustomizeAllChartAreas();
69      chart.ChartAreas[0].CursorX.Interval = 1;
70      chart.ChartAreas[0].CursorY.Interval = 1;
71      chart.ChartAreas[0].AxisX.ScaleView.Zoomable = !this.isSelecting;
72      chart.ChartAreas[0].AxisY.ScaleView.Zoomable = !this.isSelecting;
73    }
74
75    public new RunCollection Content {
76      get { return (RunCollection)base.Content; }
77      set { base.Content = value; }
78    }
79    public IStringConvertibleMatrix Matrix {
80      get { return this.Content; }
81    }
82
83    protected override void RegisterContentEvents() {
84      base.RegisterContentEvents();
85      Content.Reset += new EventHandler(Content_Reset);
86      Content.ColumnNamesChanged += new EventHandler(Content_ColumnNamesChanged);
87      Content.ItemsAdded += new HeuristicLab.Collections.CollectionItemsChangedEventHandler<IRun>(Content_ItemsAdded);
88      Content.ItemsRemoved += new HeuristicLab.Collections.CollectionItemsChangedEventHandler<IRun>(Content_ItemsRemoved);
89      Content.CollectionReset += new HeuristicLab.Collections.CollectionItemsChangedEventHandler<IRun>(Content_CollectionReset);
90      RegisterRunEvents(Content);
91    }
92    protected override void DeregisterContentEvents() {
93      base.DeregisterContentEvents();
94      Content.Reset -= new EventHandler(Content_Reset);
95      Content.ColumnNamesChanged -= new EventHandler(Content_ColumnNamesChanged);
96      Content.ItemsAdded -= new HeuristicLab.Collections.CollectionItemsChangedEventHandler<IRun>(Content_ItemsAdded);
97      Content.ItemsRemoved -= new HeuristicLab.Collections.CollectionItemsChangedEventHandler<IRun>(Content_ItemsRemoved);
98      Content.CollectionReset -= new HeuristicLab.Collections.CollectionItemsChangedEventHandler<IRun>(Content_CollectionReset);
99      DeregisterRunEvents(Content);
100    }
101    protected virtual void RegisterRunEvents(IEnumerable<IRun> runs) {
102      foreach (IRun run in runs)
103        run.Changed += new EventHandler(run_Changed);
104    }
105    protected virtual void DeregisterRunEvents(IEnumerable<IRun> runs) {
106      foreach (IRun run in runs)
107        run.Changed -= new EventHandler(run_Changed);
108    }
109
110    private void Content_CollectionReset(object sender, HeuristicLab.Collections.CollectionItemsChangedEventArgs<IRun> e) {
111      DeregisterRunEvents(e.OldItems);
112      RegisterRunEvents(e.Items);
113    }
114    private void Content_ItemsRemoved(object sender, HeuristicLab.Collections.CollectionItemsChangedEventArgs<IRun> e) {
115      DeregisterRunEvents(e.Items);
116    }
117    private void Content_ItemsAdded(object sender, HeuristicLab.Collections.CollectionItemsChangedEventArgs<IRun> e) {
118      RegisterRunEvents(e.Items);
119    }
120    private void run_Changed(object sender, EventArgs e) {
121      if (InvokeRequired)
122        this.Invoke(new EventHandler(run_Changed), sender, e);
123      else {
124        IRun run = (IRun)sender;
125        UpdateRun(run);
126      }
127    }
128
129    private void UpdateRun(IRun run) {
130      DataPoint point = runToDataPointMapping[run];
131      if (point != null) {
132        point.Color = run.Color;
133        if (!run.Visible) {
134          this.chart.Series[0].Points.Remove(point);
135          runToDataPointMapping.Remove(run);
136          UpdateCursorInterval();
137          chart.ChartAreas[0].RecalculateAxesScale();
138        }
139      } else {
140        AddDataPoint(run);
141        UpdateCursorInterval();
142        chart.ChartAreas[0].RecalculateAxesScale();
143      }
144
145
146      if (this.chart.Series[0].Points.Count == 0)
147        noRunsLabel.Visible = true;
148      else
149        noRunsLabel.Visible = false;
150    }
151
152    protected override void OnContentChanged() {
153      base.OnContentChanged();
154      this.categoricalMapping.Clear();
155      UpdateComboBoxes();
156      UpdateDataPoints();
157    }
158    private void Content_ColumnNamesChanged(object sender, EventArgs e) {
159      if (InvokeRequired)
160        Invoke(new EventHandler(Content_ColumnNamesChanged), sender, e);
161      else
162        UpdateComboBoxes();
163    }
164
165    private void UpdateComboBoxes() {
166      string selectedXAxis = (string)this.xAxisComboBox.SelectedItem;
167      string selectedYAxis = (string)this.yAxisComboBox.SelectedItem;
168      string selectedSizeAxis = (string)this.sizeComboBox.SelectedItem;
169      this.xAxisComboBox.Items.Clear();
170      this.yAxisComboBox.Items.Clear();
171      this.sizeComboBox.Items.Clear();
172      if (Content != null) {
173        string[] additionalAxisDimension = Enum.GetNames(typeof(AxisDimension));
174        this.xAxisComboBox.Items.AddRange(additionalAxisDimension);
175        this.xAxisComboBox.Items.AddRange(Matrix.ColumnNames.ToArray());
176        this.yAxisComboBox.Items.AddRange(additionalAxisDimension);
177        this.yAxisComboBox.Items.AddRange(Matrix.ColumnNames.ToArray());
178        string[] additionalSizeDimension = Enum.GetNames(typeof(SizeDimension));
179        this.sizeComboBox.Items.AddRange(additionalSizeDimension);
180        this.sizeComboBox.Items.AddRange(Matrix.ColumnNames.ToArray());
181        this.sizeComboBox.SelectedItem = SizeDimension.Constant.ToString();
182
183        bool changed = false;
184        if (selectedXAxis != null && xAxisComboBox.Items.Contains(selectedXAxis)) {
185          xAxisComboBox.SelectedItem = selectedXAxis;
186          changed = true;
187        }
188        if (selectedYAxis != null && yAxisComboBox.Items.Contains(selectedYAxis)) {
189          yAxisComboBox.SelectedItem = selectedYAxis;
190          changed = true;
191        }
192        if (selectedSizeAxis != null && sizeComboBox.Items.Contains(selectedSizeAxis)) {
193          sizeComboBox.SelectedItem = selectedSizeAxis;
194          changed = true;
195        }
196        if (changed)
197          UpdateDataPoints();
198      }
199    }
200
201    private void Content_Reset(object sender, EventArgs e) {
202      if (InvokeRequired)
203        Invoke(new EventHandler(Content_Reset), sender, e);
204      else {
205        this.categoricalMapping.Clear();
206        UpdateDataPoints();
207      }
208    }
209
210    private void UpdateDataPoints() {
211      Series series = this.chart.Series[0];
212      series.Points.Clear();
213      runToDataPointMapping.Clear();
214      if (Content != null) {
215        foreach (IRun run in this.Content)
216          this.AddDataPoint(run);
217
218        //check to correct max bubble size
219        if (this.chart.Series[0].Points.Select(p => p.YValues[1]).Distinct().Count() == 1)
220          this.chart.Series[0]["BubbleMaxSize"] = "2";
221        else
222          this.chart.Series[0]["BubbleMaxSize"] = "7";
223
224        if (this.chart.Series[0].Points.Count == 0)
225          noRunsLabel.Visible = true;
226        else {
227          noRunsLabel.Visible = false;
228          UpdateCursorInterval();
229        }
230      }
231    }
232    private void AddDataPoint(IRun run) {
233      double? xValue;
234      double? yValue;
235      double? sizeValue;
236      Series series = this.chart.Series[0];
237
238      xValue = GetValue(run, xAxisValue);
239      yValue = GetValue(run, yAxisValue);
240      sizeValue = GetValue(run, sizeAxisValue);
241
242      if (xValue.HasValue && yValue.HasValue && sizeValue.HasValue) {
243        xValue = xValue.Value;
244        if (!xJitterFactor.IsAlmost(0.0))
245          xValue += 0.1 * GetXJitter(run) * xJitterFactor * (this.chart.ChartAreas[0].AxisX.Maximum - this.chart.ChartAreas[0].AxisX.Minimum);
246        yValue = yValue.Value;
247        if (!yJitterFactor.IsAlmost(0.0))
248          yValue += 0.1 * GetYJitter(run) * yJitterFactor * (this.chart.ChartAreas[0].AxisY.Maximum - this.chart.ChartAreas[0].AxisY.Minimum);
249        if (run.Visible) {
250          DataPoint point = new DataPoint(xValue.Value, new double[] { yValue.Value, sizeValue.Value });
251          point.Tag = run;
252          point.Color = run.Color;
253          series.Points.Add(point);
254          runToDataPointMapping[run] = point;
255        }
256      }
257    }
258    private double? GetValue(IRun run, string columnName) {
259      if (run == null || string.IsNullOrEmpty(columnName))
260        return null;
261
262      if (Enum.IsDefined(typeof(AxisDimension), columnName)) {
263        AxisDimension axisDimension = (AxisDimension)Enum.Parse(typeof(AxisDimension), columnName);
264        return GetValue(run, axisDimension);
265      } else if (Enum.IsDefined(typeof(SizeDimension), columnName)) {
266        SizeDimension sizeDimension = (SizeDimension)Enum.Parse(typeof(SizeDimension), columnName);
267        return GetValue(run, sizeDimension);
268      } else {
269        int columnIndex = Matrix.ColumnNames.ToList().IndexOf(columnName);
270        IItem value = Content.GetValue(run, columnIndex);
271        if (value == null)
272          return null;
273
274        DoubleValue doubleValue = value as DoubleValue;
275        IntValue intValue = value as IntValue;
276        TimeSpanValue timeSpanValue = value as TimeSpanValue;
277        double? ret = null;
278        if (doubleValue != null) {
279          if (!double.IsNaN(doubleValue.Value) && !double.IsInfinity(doubleValue.Value))
280            ret = doubleValue.Value;
281        } else if (intValue != null)
282          ret = intValue.Value;
283        else if (timeSpanValue != null) {
284          ret = timeSpanValue.Value.TotalSeconds;
285        } else
286          ret = GetCategoricalValue(columnIndex, value.ToString());
287
288        return ret;
289      }
290    }
291    private double GetCategoricalValue(int dimension, string value) {
292      if (!this.categoricalMapping.ContainsKey(dimension))
293        this.categoricalMapping[dimension] = new Dictionary<object, double>();
294      if (!this.categoricalMapping[dimension].ContainsKey(value)) {
295        if (this.categoricalMapping[dimension].Values.Count == 0)
296          this.categoricalMapping[dimension][value] = 1.0;
297        else
298          this.categoricalMapping[dimension][value] = this.categoricalMapping[dimension].Values.Max() + 1.0;
299      }
300      return this.categoricalMapping[dimension][value];
301    }
302    private double GetValue(IRun run, AxisDimension axisDimension) {
303      double value = double.NaN;
304      switch (axisDimension) {
305        case AxisDimension.Index: {
306            value = Content.ToList().IndexOf(run);
307            break;
308          }
309        default: {
310            throw new ArgumentException("No handling strategy for " + axisDimension.ToString() + " is defined.");
311          }
312      }
313      return value;
314    }
315    private double GetValue(IRun run, SizeDimension sizeDimension) {
316      double value = double.NaN;
317      switch (sizeDimension) {
318        case SizeDimension.Constant: {
319            value = 2;
320            break;
321          }
322        default: {
323            throw new ArgumentException("No handling strategy for " + sizeDimension.ToString() + " is defined.");
324          }
325      }
326      return value;
327    }
328    private void UpdateCursorInterval() {
329      Series series = chart.Series[0];
330      double[] xValues = (from point in series.Points
331                          where !point.IsEmpty
332                          select point.XValue)
333                    .DefaultIfEmpty(1.0)
334                    .ToArray();
335      double[] yValues = (from point in series.Points
336                          where !point.IsEmpty
337                          select point.YValues[0])
338                    .DefaultIfEmpty(1.0)
339                    .ToArray();
340
341      double xRange = xValues.Max() - xValues.Min();
342      double yRange = yValues.Max() - yValues.Min();
343      if (xRange.IsAlmost(0.0)) xRange = 1.0;
344      if (yRange.IsAlmost(0.0)) yRange = 1.0;
345      double xDigits = (int)Math.Log10(xRange) - 3;
346      double yDigits = (int)Math.Log10(yRange) - 3;
347      double xZoomInterval = Math.Pow(10, xDigits);
348      double yZoomInterval = Math.Pow(10, yDigits);
349      this.chart.ChartAreas[0].CursorX.Interval = xZoomInterval;
350      this.chart.ChartAreas[0].CursorY.Interval = yZoomInterval;
351
352      //code to handle TimeSpanValues correct
353      int axisDimensionCount = Enum.GetNames(typeof(AxisDimension)).Count();
354      int columnIndex = xAxisComboBox.SelectedIndex - axisDimensionCount;
355      if (columnIndex >= 0 && Content.GetValue(0, columnIndex) is TimeSpanValue)
356        this.chart.ChartAreas[0].CursorX.Interval = 1;
357      columnIndex = yAxisComboBox.SelectedIndex - axisDimensionCount;
358      if (columnIndex >= 0 && Content.GetValue(0, columnIndex) is TimeSpanValue)
359        this.chart.ChartAreas[0].CursorY.Interval = 1;
360    }
361
362    #region drag and drop and tooltip
363    private IRun draggedRun;
364    private void chart_MouseDown(object sender, MouseEventArgs e) {
365      HitTestResult h = this.chart.HitTest(e.X, e.Y);
366      if (h.ChartElementType == ChartElementType.DataPoint) {
367        IRun run = (IRun)((DataPoint)h.Object).Tag;
368        if (e.Clicks >= 2) {
369          IContentView view = MainFormManager.MainForm.ShowContent(run);
370          if (view != null) {
371            view.ReadOnly = this.ReadOnly;
372            view.Locked = this.Locked;
373          }
374        } else
375          this.draggedRun = run;
376        this.chart.ChartAreas[0].CursorX.SetSelectionPosition(double.NaN, double.NaN);
377        this.chart.ChartAreas[0].CursorY.SetSelectionPosition(double.NaN, double.NaN);
378      }
379    }
380
381    private void chart_MouseUp(object sender, MouseEventArgs e) {
382      if (isSelecting) {
383        System.Windows.Forms.DataVisualization.Charting.Cursor xCursor = chart.ChartAreas[0].CursorX;
384        System.Windows.Forms.DataVisualization.Charting.Cursor yCursor = chart.ChartAreas[0].CursorY;
385
386        double minX = Math.Min(xCursor.SelectionStart, xCursor.SelectionEnd);
387        double maxX = Math.Max(xCursor.SelectionStart, xCursor.SelectionEnd);
388        double minY = Math.Min(yCursor.SelectionStart, yCursor.SelectionEnd);
389        double maxY = Math.Max(yCursor.SelectionStart, yCursor.SelectionEnd);
390
391        //check for click to select model
392        if (minX == maxX && minY == maxY) {
393          HitTestResult hitTest = chart.HitTest(e.X, e.Y);
394          if (hitTest.ChartElementType == ChartElementType.DataPoint) {
395            int pointIndex = hitTest.PointIndex;
396            IRun run = (IRun)this.chart.Series[0].Points[pointIndex].Tag;
397            run.Color = colorDialog.Color;
398          }
399        } else {
400          List<DataPoint> selectedPoints = new List<DataPoint>();
401          foreach (DataPoint p in this.chart.Series[0].Points) {
402            if (p.XValue >= minX && p.XValue < maxX &&
403              p.YValues[0] >= minY && p.YValues[0] < maxY) {
404              selectedPoints.Add(p);
405            }
406          }
407          foreach (DataPoint p in selectedPoints) {
408            IRun run = (IRun)p.Tag;
409            run.Color = colorDialog.Color;
410          }
411        }
412        this.chart.ChartAreas[0].CursorX.SelectionStart = this.chart.ChartAreas[0].CursorX.SelectionEnd;
413        this.chart.ChartAreas[0].CursorY.SelectionStart = this.chart.ChartAreas[0].CursorY.SelectionEnd;
414      }
415    }
416
417    private void chart_MouseMove(object sender, MouseEventArgs e) {
418      HitTestResult h = this.chart.HitTest(e.X, e.Y);
419      if (!Locked) {
420        if (this.draggedRun != null && h.ChartElementType != ChartElementType.DataPoint) {
421          DataObject data = new DataObject();
422          data.SetData("Type", draggedRun.GetType());
423          data.SetData("Value", draggedRun);
424          if (ReadOnly)
425            DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link);
426          else {
427            DragDropEffects result = DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link | DragDropEffects.Move);
428            if ((result & DragDropEffects.Move) == DragDropEffects.Move)
429              Content.Remove(draggedRun);
430          }
431          this.chart.ChartAreas[0].AxisX.ScaleView.Zoomable = !isSelecting;
432          this.chart.ChartAreas[0].AxisY.ScaleView.Zoomable = !isSelecting;
433          this.draggedRun = null;
434        }
435      }
436
437      string newTooltipText = string.Empty;
438      string oldTooltipText;
439      if (h.ChartElementType == ChartElementType.DataPoint) {
440        IRun run = (IRun)((DataPoint)h.Object).Tag;
441        newTooltipText = BuildTooltip(run);
442      } else if (h.ChartElementType == ChartElementType.AxisLabels) {
443        newTooltipText = ((CustomLabel)h.Object).ToolTip;
444      }
445
446      oldTooltipText = this.tooltip.GetToolTip(chart);
447      if (newTooltipText != oldTooltipText)
448        this.tooltip.SetToolTip(chart, newTooltipText);
449    }
450
451    private string BuildTooltip(IRun run) {
452      string tooltip;
453      tooltip = run.Name + System.Environment.NewLine;
454
455      double? xValue = this.GetValue(run, (string)xAxisComboBox.SelectedItem);
456      double? yValue = this.GetValue(run, (string)yAxisComboBox.SelectedItem);
457      double? sizeValue = this.GetValue(run, (string)sizeComboBox.SelectedItem);
458
459      string xString = xValue == null ? string.Empty : xValue.Value.ToString();
460      string yString = yValue == null ? string.Empty : yValue.Value.ToString();
461      string sizeString = sizeValue == null ? string.Empty : sizeValue.Value.ToString();
462
463      //code to handle TimeSpanValues correct
464      int axisDimensionCount = Enum.GetNames(typeof(AxisDimension)).Count();
465      int columnIndex = xAxisComboBox.SelectedIndex - axisDimensionCount;
466      if (xValue.HasValue && columnIndex > 0 && Content.GetValue(0, columnIndex) is TimeSpanValue) {
467        TimeSpan time = TimeSpan.FromSeconds(xValue.Value);
468        xString = string.Format("{0:00}:{1:00}:{2:00.00}", (int)time.TotalHours, time.Minutes, time.Seconds);
469      }
470      columnIndex = yAxisComboBox.SelectedIndex - axisDimensionCount;
471      if (yValue.HasValue && columnIndex > 0 && Content.GetValue(0, columnIndex) is TimeSpanValue) {
472        TimeSpan time = TimeSpan.FromSeconds(yValue.Value);
473        yString = string.Format("{0:00}:{1:00}:{2:00.00}", (int)time.TotalHours, time.Minutes, time.Seconds);
474      }
475
476      tooltip += xAxisComboBox.SelectedItem + " : " + xString + Environment.NewLine;
477      tooltip += yAxisComboBox.SelectedItem + " : " + yString + Environment.NewLine;
478      tooltip += sizeComboBox.SelectedItem + " : " + sizeString + Environment.NewLine;
479
480      return tooltip;
481    }
482    #endregion
483
484    #region GUI events and updating
485    private double GetXJitter(IRun run) {
486      if (!this.xJitter.ContainsKey(run))
487        this.xJitter[run] = random.NextDouble() * 2.0 - 1.0;
488      return this.xJitter[run];
489    }
490    private double GetYJitter(IRun run) {
491      if (!this.yJitter.ContainsKey(run))
492        this.yJitter[run] = random.NextDouble() * 2.0 - 1.0;
493      return this.yJitter[run];
494    }
495    private void jitterTrackBar_ValueChanged(object sender, EventArgs e) {
496      this.xJitterFactor = xTrackBar.Value / 100.0;
497      this.yJitterFactor = yTrackBar.Value / 100.0;
498      this.UpdateDataPoints();
499    }
500
501    private void AxisComboBox_SelectedIndexChanged(object sender, EventArgs e) {
502      bool axisSelected = xAxisComboBox.SelectedIndex != -1 && yAxisComboBox.SelectedIndex != -1;
503      xTrackBar.Enabled = yTrackBar.Enabled = axisSelected;
504      colorXAxisButton.Enabled = colorYAxisButton.Enabled = axisSelected;
505
506      if (!xAxisComboBox.DroppedDown)
507        xAxisValue = (string)xAxisComboBox.SelectedItem;
508      if (!yAxisComboBox.DroppedDown)
509        yAxisValue = (string)yAxisComboBox.SelectedItem;
510      if (!sizeComboBox.DroppedDown)
511        sizeAxisValue = (string)sizeComboBox.SelectedItem;
512
513      UpdateDataPoints();
514      UpdateAxisLabels();
515    }
516    private void UpdateAxisLabels() {
517      Axis xAxis = this.chart.ChartAreas[0].AxisX;
518      Axis yAxis = this.chart.ChartAreas[0].AxisY;
519      int axisDimensionCount = Enum.GetNames(typeof(AxisDimension)).Count();
520      SetCustomAxisLabels(xAxis, xAxisComboBox.SelectedIndex - axisDimensionCount);
521      SetCustomAxisLabels(yAxis, yAxisComboBox.SelectedIndex - axisDimensionCount);
522      if (xAxisComboBox.SelectedItem != null)
523        xAxis.Title = xAxisComboBox.SelectedItem.ToString();
524      if (yAxisComboBox.SelectedItem != null)
525        yAxis.Title = yAxisComboBox.SelectedItem.ToString();
526    }
527
528    private void chart_AxisViewChanged(object sender, System.Windows.Forms.DataVisualization.Charting.ViewEventArgs e) {
529      this.UpdateAxisLabels();
530    }
531
532    private void SetCustomAxisLabels(Axis axis, int dimension) {
533      axis.CustomLabels.Clear();
534      if (categoricalMapping.ContainsKey(dimension)) {
535        foreach (var pair in categoricalMapping[dimension]) {
536          string labelText = pair.Key.ToString();
537          CustomLabel label = new CustomLabel();
538          label.ToolTip = labelText;
539          if (labelText.Length > 25)
540            labelText = labelText.Substring(0, 25) + " ... ";
541          label.Text = labelText;
542          label.GridTicks = GridTickTypes.TickMark;
543          label.FromPosition = pair.Value - 0.5;
544          label.ToPosition = pair.Value + 0.5;
545          axis.CustomLabels.Add(label);
546        }
547      } else if (dimension > 0 && Content.GetValue(0, dimension) is TimeSpanValue) {
548        this.chart.ChartAreas[0].RecalculateAxesScale();
549        for (double i = axis.Minimum; i <= axis.Maximum; i += axis.LabelStyle.Interval) {
550          TimeSpan time = TimeSpan.FromSeconds(i);
551          string x = string.Format("{0:00}:{1:00}:{2:00}", (int)time.Hours, time.Minutes, time.Seconds);
552          axis.CustomLabels.Add(i - axis.LabelStyle.Interval / 2, i + axis.LabelStyle.Interval / 2, x);
553        }
554      }
555    }
556
557    private void zoomButton_CheckedChanged(object sender, EventArgs e) {
558      this.isSelecting = selectButton.Checked;
559      this.colorButton.Enabled = this.isSelecting;
560      this.chart.ChartAreas[0].AxisX.ScaleView.Zoomable = !isSelecting;
561      this.chart.ChartAreas[0].AxisY.ScaleView.Zoomable = !isSelecting;
562    }
563    private void colorButton_Click(object sender, EventArgs e) {
564      if (colorDialog.ShowDialog(this) == DialogResult.OK) {
565        this.colorButton.Image = this.GenerateImage(16, 16, this.colorDialog.Color);
566      }
567    }
568    private Image GenerateImage(int width, int height, Color fillColor) {
569      Image colorImage = new Bitmap(width, height);
570      using (Graphics gfx = Graphics.FromImage(colorImage)) {
571        using (SolidBrush brush = new SolidBrush(fillColor)) {
572          gfx.FillRectangle(brush, 0, 0, width, height);
573        }
574      }
575      return colorImage;
576    }
577
578    private void openBoxPlotViewToolStripMenuItem_Click(object sender, EventArgs e) {
579      RunCollectionBoxPlotView boxplotView = new RunCollectionBoxPlotView();
580      boxplotView.Content = this.Content;
581      boxplotView.xAxisComboBox.SelectedItem = xAxisComboBox.SelectedItem;
582      boxplotView.yAxisComboBox.SelectedItem = yAxisComboBox.SelectedItem;
583      boxplotView.Show();
584    }
585    #endregion
586
587    #region automatic coloring
588    private void colorXAxisButton_Click(object sender, EventArgs e) {
589      ColorRuns(xAxisValue);
590    }
591
592    private void colorYAxisButton_Click(object sender, EventArgs e) {
593      ColorRuns(yAxisValue);
594    }
595
596    private void ColorRuns(string axisValue) {
597      var runs = Content.Select(r => new { Run = r, Value = GetValue(r, axisValue) }).Where(r => r.Value.HasValue);
598      double minValue = runs.Min(r => r.Value.Value);
599      double maxValue = runs.Max(r => r.Value.Value);
600      double range = maxValue - minValue;
601
602      foreach (var r in runs) {
603        int colorIndex = 0;
604        if (!range.IsAlmost(0)) colorIndex = (int)((ColorGradient.Colors.Count - 1) * (r.Value.Value - minValue) / (maxValue - minValue));
605        r.Run.Color = ColorGradient.Colors[colorIndex];
606      }
607    }
608    #endregion
609  }
610}
Note: See TracBrowser for help on using the repository browser.