Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 3454 was 3454, checked in by swagner, 14 years ago

Adapted views according the new read-only property (#973)

File size: 16.5 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.ComponentModel;
25using System.Data;
26using System.Drawing;
27using System.Linq;
28using System.Text;
29using System.Windows.Forms;
30using HeuristicLab.MainForm.WindowsForms;
31using HeuristicLab.MainForm;
32using System.Windows.Forms.DataVisualization.Charting;
33using HeuristicLab.Common;
34using HeuristicLab.Core;
35using HeuristicLab.Data;
36
37namespace HeuristicLab.Optimization.Views {
38  [View("RunCollection BubbleChart")]
39  [Content(typeof(RunCollection), false)]
40  public partial class RunCollectionBubbleChartView : AsynchronousContentView {
41    private const string constantLabel = "constant";
42    private Dictionary<int, Dictionary<object, double>> categoricalMapping;
43    private Dictionary<IRun, double> xJitter;
44    private Dictionary<IRun, double> yJitter;
45    private double xJitterFactor = 0.0;
46    private double yJitterFactor = 0.0;
47    private Random random;
48    private bool isSelecting = false;
49
50    public RunCollectionBubbleChartView() {
51      InitializeComponent();
52      Caption = "Run Collection Bubble Chart";
53
54      this.categoricalMapping = new Dictionary<int, Dictionary<object, double>>();
55      this.xJitter = new Dictionary<IRun, double>();
56      this.yJitter = new Dictionary<IRun, double>();
57      this.random = new Random();
58      this.colorDialog.Color = Color.Black;
59      this.colorButton.Image = this.GenerateImage(16, 16, this.colorDialog.Color);
60      this.isSelecting = false;
61
62      this.chart.Series[0]["BubbleMaxSize"] = "0";
63      this.chart.Series[0]["BubbleMaxScale"] = "Auto";
64      this.chart.Series[0]["BubbleMinScale"] = "Auto";
65      this.chart.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
66      this.chart.ChartAreas[0].CursorY.IsUserSelectionEnabled = true;
67      this.chart.ChartAreas[0].AxisX.ScaleView.Zoomable = !this.isSelecting;
68      this.chart.ChartAreas[0].AxisY.ScaleView.Zoomable = !this.isSelecting;
69      this.chart.ChartAreas[0].CursorX.Interval = 0;
70      this.chart.ChartAreas[0].CursorY.Interval = 0;
71    }
72
73    public RunCollectionBubbleChartView(RunCollection content)
74      : this() {
75      Content = content;
76    }
77
78    public new RunCollection Content {
79      get { return (RunCollection)base.Content; }
80      set { base.Content = value; }
81    }
82
83    public IStringConvertibleMatrix Matrix {
84      get { return this.Content; }
85    }
86
87    protected override void RegisterContentEvents() {
88      base.RegisterContentEvents();
89      Content.Reset += new EventHandler(Content_Reset);
90      Content.ColumnNamesChanged += new EventHandler(Content_ColumnNamesChanged);
91      Content.ItemsAdded += new HeuristicLab.Collections.CollectionItemsChangedEventHandler<IRun>(Content_ItemsAdded);
92      Content.ItemsRemoved += new HeuristicLab.Collections.CollectionItemsChangedEventHandler<IRun>(Content_ItemsRemoved);
93      Content.CollectionReset += new HeuristicLab.Collections.CollectionItemsChangedEventHandler<IRun>(Content_CollectionReset);
94      RegisterRunEvents(Content);
95    }
96    protected virtual void RegisterRunEvents(IEnumerable<IRun> runs) {
97      foreach (IRun run in runs)
98        run.Changed += new EventHandler(run_Changed);
99    }
100    protected override void DeregisterContentEvents() {
101      base.DeregisterContentEvents();
102      Content.Reset -= new EventHandler(Content_Reset);
103      Content.ColumnNamesChanged -= new EventHandler(Content_ColumnNamesChanged);
104      Content.ItemsAdded -= new HeuristicLab.Collections.CollectionItemsChangedEventHandler<IRun>(Content_ItemsAdded);
105      Content.ItemsRemoved -= new HeuristicLab.Collections.CollectionItemsChangedEventHandler<IRun>(Content_ItemsRemoved);
106      Content.CollectionReset -= new HeuristicLab.Collections.CollectionItemsChangedEventHandler<IRun>(Content_CollectionReset);
107      DeregisterRunEvents(Content);
108    }
109    protected virtual void DeregisterRunEvents(IEnumerable<IRun> runs) {
110      foreach (IRun run in runs)
111        run.Changed -= new EventHandler(run_Changed);
112    }
113
114    private void Content_CollectionReset(object sender, HeuristicLab.Collections.CollectionItemsChangedEventArgs<IRun> e) {
115      DeregisterRunEvents(e.OldItems);
116      RegisterRunEvents(e.Items);
117    }
118    private void Content_ItemsRemoved(object sender, HeuristicLab.Collections.CollectionItemsChangedEventArgs<IRun> e) {
119      DeregisterRunEvents(e.Items);
120    }
121    private void Content_ItemsAdded(object sender, HeuristicLab.Collections.CollectionItemsChangedEventArgs<IRun> e) {
122      RegisterRunEvents(e.Items);
123    }
124    private void run_Changed(object sender, EventArgs e) {
125      IRun run = (IRun)sender;
126      DataPoint point = this.chart.Series[0].Points.Where(p => p.Tag == run).SingleOrDefault();
127      if (point != null) {
128        point.Color = run.Color;
129        if (!run.Visible)
130          this.chart.Series[0].Points.Remove(point);
131      } else
132        AddDataPoint(run);
133    }
134
135    protected override void OnContentChanged() {
136      base.OnContentChanged();
137      this.categoricalMapping.Clear();
138      this.UpdateComboBoxes();
139    }
140    private void Content_ColumnNamesChanged(object sender, EventArgs e) {
141      if (InvokeRequired)
142        Invoke(new EventHandler(Content_ColumnNamesChanged), sender, e);
143      else
144        UpdateComboBoxes();
145    }
146
147    private void UpdateComboBoxes() {
148      this.xAxisComboBox.Items.Clear();
149      this.yAxisComboBox.Items.Clear();
150      this.sizeComboBox.Items.Clear();
151      this.xAxisComboBox.Items.AddRange(Matrix.ColumnNames.ToArray());
152      this.yAxisComboBox.Items.AddRange(Matrix.ColumnNames.ToArray());
153      this.sizeComboBox.Items.Add(constantLabel);
154      this.sizeComboBox.Items.AddRange(Matrix.ColumnNames.ToArray());
155    }
156
157    private void Content_Reset(object sender, EventArgs e) {
158      if (InvokeRequired)
159        Invoke(new EventHandler(Content_Reset), sender, e);
160      else {
161        this.categoricalMapping.Clear();
162        UpdateDataPoints();
163      }
164    }
165
166    private void UpdateDataPoints() {
167      Series series = this.chart.Series[0];
168      series.Points.Clear();
169      foreach (IRun run in this.Content)
170        this.AddDataPoint(run);
171    }
172    private void AddDataPoint(IRun run) {
173      double? xValue;
174      double? yValue;
175      double? sizeValue;
176      Series series = this.chart.Series[0];
177      int row = this.Content.ToList().IndexOf(run);
178      xValue = GetValue(row, xAxisComboBox.SelectedIndex);
179      yValue = GetValue(row, yAxisComboBox.SelectedIndex);
180      sizeValue = 1.0;
181      if (xValue.HasValue && yValue.HasValue) {
182        if (sizeComboBox.SelectedIndex > 0)
183          sizeValue = GetValue(row, sizeComboBox.SelectedIndex - 1);
184        xValue = xValue.Value + xValue.Value * GetXJitter(Content.ElementAt(row)) * xJitterFactor;
185        yValue = yValue.Value + yValue.Value * GetYJitter(Content.ElementAt(row)) * yJitterFactor;
186        if (run.Visible) {
187          DataPoint point = new DataPoint(xValue.Value, new double[] { yValue.Value, sizeValue.Value });
188          point.ToolTip = this.CreateTooltip(row);
189          point.Tag = run;
190          point.Color = run.Color;
191          series.Points.Add(point);
192        }
193      }
194    }
195    private double? GetValue(int row, int column) {
196      if (column < 0 || row < 0)
197        return null;
198
199      IItem value = Content.GetValue(row, column);
200      DoubleValue doubleValue = value as DoubleValue;
201      IntValue intValue = value as IntValue;
202      double ret;
203
204      if (doubleValue != null)
205        ret = doubleValue.Value;
206      else if (intValue != null)
207        ret = intValue.Value;
208      else
209        ret = GetCategoricalValue(column, Matrix.GetValue(row, column));
210
211      return ret;
212    }
213    private double GetCategoricalValue(int dimension, object c) {
214      if (!this.categoricalMapping.ContainsKey(dimension))
215        this.categoricalMapping[dimension] = new Dictionary<object, double>();
216      if (!this.categoricalMapping[dimension].ContainsKey(c)) {
217        if (this.categoricalMapping[dimension].Values.Count == 0)
218          this.categoricalMapping[dimension][c] = 1.0;
219        else
220          this.categoricalMapping[dimension][c] = this.categoricalMapping[dimension].Values.Max() + 1.0;
221      }
222      return this.categoricalMapping[dimension][c];
223    }
224
225    #region drag and drop
226    private IRun draggedRun;
227    private bool isDragOperationInProgress = false;
228
229    private void chart_MouseDown(object sender, MouseEventArgs e) {
230      HitTestResult h = this.chart.HitTest(e.X, e.Y);
231      if (h.ChartElementType == ChartElementType.DataPoint) {
232        IRun run =(IRun)((DataPoint)h.Object).Tag;
233        if (e.Clicks >= 2) {
234          IContentView view = MainFormManager.CreateDefaultView(run);
235          view.ReadOnly = this.ReadOnly;
236          view.Locked = this.Locked;
237          view.Show();
238        } else {
239          this.draggedRun = run;
240          this.chart.ChartAreas[0].AxisX.ScaleView.Zoomable = false;
241          this.chart.ChartAreas[0].AxisY.ScaleView.Zoomable = false;
242          this.chart.ChartAreas[0].CursorX.IsUserSelectionEnabled = false;
243          this.chart.ChartAreas[0].CursorY.IsUserSelectionEnabled = false;
244        }
245      }
246    }
247
248    private void chart_MouseUp(object sender, MouseEventArgs e) {
249      if (isDragOperationInProgress) {
250        this.isDragOperationInProgress = false;
251        this.chart.ChartAreas[0].AxisX.ScaleView.Zoomable = !isSelecting;
252        this.chart.ChartAreas[0].AxisY.ScaleView.Zoomable = !isSelecting;
253        this.chart.ChartAreas[0].CursorX.SetSelectionPosition(0, 0);
254        this.chart.ChartAreas[0].CursorY.SetSelectionPosition(0, 0);
255        this.chart.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
256        this.chart.ChartAreas[0].CursorY.IsUserSelectionEnabled = true;
257        return;
258      }
259      if (!isSelecting) return;
260      System.Windows.Forms.DataVisualization.Charting.Cursor xCursor = chart.ChartAreas[0].CursorX;
261      System.Windows.Forms.DataVisualization.Charting.Cursor yCursor = chart.ChartAreas[0].CursorY;
262
263      double minX = Math.Min(xCursor.SelectionStart, xCursor.SelectionEnd);
264      double maxX = Math.Max(xCursor.SelectionStart, xCursor.SelectionEnd);
265      double minY = Math.Min(yCursor.SelectionStart, yCursor.SelectionEnd);
266      double maxY = Math.Max(yCursor.SelectionStart, yCursor.SelectionEnd);
267
268      //check for click to select model
269      if (minX == maxX && minY == maxY) {
270        HitTestResult hitTest = chart.HitTest(e.X, e.Y);
271        if (hitTest.ChartElementType == ChartElementType.DataPoint) {
272          int pointIndex = hitTest.PointIndex;
273          IRun run = (IRun)this.chart.Series[0].Points[pointIndex].Tag;
274          run.Color = colorDialog.Color;
275        }
276      } else {
277      List<DataPoint> selectedPoints = new List<DataPoint>();
278      foreach (DataPoint p in this.chart.Series[0].Points) {
279        if (p.XValue >= minX && p.XValue < maxX &&
280          p.YValues[0] >= minY && p.YValues[0] < maxY) {
281          selectedPoints.Add(p);
282        }
283      }
284      foreach (DataPoint p in selectedPoints) {
285        IRun run = (IRun)p.Tag;
286        run.Color = colorDialog.Color;
287      }
288      xCursor.SetSelectionPosition(0, 0);
289      yCursor.SetSelectionPosition(0, 0);
290      }
291    }
292
293    private void chart_MouseMove(object sender, MouseEventArgs e) {
294      if (!Locked) {
295        HitTestResult h = this.chart.HitTest(e.X, e.Y);
296        if (this.draggedRun != null && h.ChartElementType != ChartElementType.DataPoint) {
297          this.isDragOperationInProgress = true;
298          DataObject data = new DataObject();
299          data.SetData("Type", draggedRun.GetType());
300          data.SetData("Value", draggedRun);
301          if (ReadOnly) {
302            DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link);
303          } else {
304            DragDropEffects result = DoDragDrop(data, DragDropEffects.Copy | DragDropEffects.Link | DragDropEffects.Move);
305            if ((result & DragDropEffects.Move) == DragDropEffects.Move)
306              Content.Remove(draggedRun);
307          }
308          this.draggedRun = null;
309        }
310      }
311    }
312    private void chart_LostFocus(object sender, EventArgs e) {
313      if (this.isDragOperationInProgress) {
314        this.chart.ChartAreas[0].AxisX.ScaleView.Zoomable = !isSelecting;
315        this.chart.ChartAreas[0].AxisY.ScaleView.Zoomable = !isSelecting;
316        this.chart.ChartAreas[0].CursorX.SetSelectionPosition(0, 0);
317        this.chart.ChartAreas[0].CursorY.SetSelectionPosition(0, 0);
318        this.chart.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
319        this.chart.ChartAreas[0].CursorY.IsUserSelectionEnabled = true;
320        this.isDragOperationInProgress = false;
321      }
322    }
323    #endregion
324
325    #region GUI events and updating
326    private double GetXJitter(IRun run) {
327      if (!this.xJitter.ContainsKey(run))
328        this.xJitter[run] = random.NextDouble() * 2.0 - 1.0;
329      return this.xJitter[run];
330    }
331    private double GetYJitter(IRun run) {
332      if (!this.yJitter.ContainsKey(run))
333        this.yJitter[run] = random.NextDouble() * 2.0 - 1.0;
334      return this.yJitter[run];
335    }
336    private void jitterTrackBar_ValueChanged(object sender, EventArgs e) {
337      this.xJitterFactor = xTrackBar.Value / 100.0;
338      this.yJitterFactor = yTrackBar.Value / 100.0;
339      this.UpdateDataPoints();
340    }
341
342    private void AxisComboBox_SelectedIndexChanged(object sender, EventArgs e) {
343      UpdateDataPoints();
344      UpdateAxisLabels();
345    }
346    private void UpdateAxisLabels() {
347      Axis xAxis = this.chart.ChartAreas[0].AxisX;
348      Axis yAxis = this.chart.ChartAreas[0].AxisY;
349      SetCustomAxisLabels(xAxis, xAxisComboBox.SelectedIndex);
350      SetCustomAxisLabels(yAxis, yAxisComboBox.SelectedIndex);
351    }
352    private void SetCustomAxisLabels(Axis axis, int dimension) {
353      axis.CustomLabels.Clear();
354      if (categoricalMapping.ContainsKey(dimension)) {
355        CustomLabel label = null;
356        foreach (var pair in categoricalMapping[dimension]) {
357          label = axis.CustomLabels.Add(pair.Value - 0.5, pair.Value + 0.5, pair.Key.ToString());
358          label.GridTicks = GridTickTypes.TickMark;
359        }
360        axis.IsLabelAutoFit = false;
361        axis.LabelStyle.Enabled = true;
362        axis.LabelStyle.Angle = 0;
363        axis.LabelStyle.TruncatedLabels = true;
364      }
365    }
366
367    private string CreateTooltip(int runIndex) {
368      StringBuilder builder = new StringBuilder();
369      builder.AppendLine(this.Content.ElementAt(runIndex).Name);
370      int columnIndex = 0;
371      foreach (string columnName in Matrix.ColumnNames) {
372        builder.Append(columnName);
373        builder.Append(": ");
374        builder.AppendLine(Matrix.GetValue(runIndex, columnIndex));
375        columnIndex++;
376      }
377      return builder.ToString();
378    }
379
380    private void zoomButton_CheckedChanged(object sender, EventArgs e) {
381      this.isSelecting = selectButton.Checked;
382      this.colorButton.Enabled = this.isSelecting;
383      this.chart.ChartAreas[0].AxisX.ScaleView.Zoomable = !isSelecting;
384      this.chart.ChartAreas[0].AxisY.ScaleView.Zoomable = !isSelecting;
385    }
386
387    private void colorButton_Click(object sender, EventArgs e) {
388      if (colorDialog.ShowDialog(this) == DialogResult.OK) {
389        this.colorButton.Image = this.GenerateImage(16, 16, this.colorDialog.Color);
390      }
391    }
392    private Image GenerateImage(int width, int height, Color fillColor) {
393      Image colorImage = new Bitmap(width, height);
394      using (Graphics gfx = Graphics.FromImage(colorImage)) {
395        using (SolidBrush brush = new SolidBrush(fillColor)) {
396          gfx.FillRectangle(brush, 0, 0, width, height);
397        }
398      }
399      return colorImage;
400    }
401    #endregion
402  }
403}
Note: See TracBrowser for help on using the repository browser.