Free cookie consent management tool by TermsFeed Policy Generator

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

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

minor changes in RunCollectionBubbleChartView (ticket #970)

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