Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 5370 was 5348, checked in by mkommend, 14 years ago

Added functionality to resize bubbles although the size combobox is set to constant (ticket #1056).

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