Free cookie consent management tool by TermsFeed Policy Generator

source: branches/BubbleChart/HeuristicLab.Optimization.BubbleChart/3.3/BubbleChartView.cs @ 12417

Last change on this file since 12417 was 12389, checked in by pfleck, 10 years ago

#2379 Add root item of RecursiveDataItem to tree view.

File size: 10.0 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 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.Linq;
25using System.Windows.Forms;
26using System.Windows.Forms.DataVisualization.Charting;
27using HeuristicLab.Common;
28using HeuristicLab.Core;
29using HeuristicLab.Core.Views;
30using HeuristicLab.Data;
31using HeuristicLab.MainForm;
32
33namespace HeuristicLab.Optimization.BubbleChart {
34  [View("Bubble Chart (Recursive)")]
35  [Content(typeof(RecursiveDataItem), false)]
36  public partial class BubbleChartView : ItemView {
37
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 readonly Dictionary<RecursiveDataItem, int> itemToIndexMapping = new Dictionary<RecursiveDataItem, int>();
46    private readonly Dictionary<string, Dictionary<object, double>> categoricalMapping = new Dictionary<string, Dictionary<object, double>>();
47
48    public new RecursiveDataItem Content {
49      get { return (RecursiveDataItem)base.Content; }
50      set { base.Content = value; }
51    }
52
53    public BubbleChartView() {
54      InitializeComponent();
55    }
56
57    protected override void OnContentChanged() {
58      base.OnContentChanged();
59
60      UpdateTreeView();
61      UpdateComboBoxes();
62      UpdateDataPoints();
63      //UpdateCaption();
64    }
65
66    #region Tree Queries
67    private IEnumerable<string> GetAvailableKeys() {
68      var collector = new List<string>();
69      foreach (TreeNode node in treeView.Nodes)
70        GetAvailableKeys(node, collector);
71      return collector.Distinct();
72    }
73    private void GetAvailableKeys(TreeNode node, List<string> collector) {
74      var item = (RecursiveDataItem)node.Tag;
75      if (node.Checked)
76        collector.AddRange(item.Data.Keys);
77      foreach (TreeNode child in node.Nodes)
78        GetAvailableKeys(child, collector);
79    }
80
81    private IEnumerable<RecursiveDataItem> GetAvailableItems() {
82      var collector = new List<RecursiveDataItem>();
83      foreach (TreeNode child in treeView.Nodes)
84        GetAvailableItems(child, collector);
85      return collector;
86    }
87
88    private void GetAvailableItems(TreeNode node, List<RecursiveDataItem> collector) {
89      var item = (RecursiveDataItem)node.Tag;
90      if (node.Checked)
91        collector.Add(item);
92      foreach (TreeNode child in node.Nodes)
93        GetAvailableItems(child, collector);
94    }
95    #endregion
96
97    #region Update Controls
98    private void UpdateTreeView() {
99      treeView.Nodes.Clear();
100
101      if (Content != null) {
102        treeView.Nodes.Add(CreateTreeNode(Content));
103      }
104
105      treeView.ExpandAll();
106      splitContainer.Panel1Collapsed = treeView.Nodes.Count == 0;
107    }
108    private TreeNode CreateTreeNode(RecursiveDataItem item) {
109      var node = new TreeNode(item.Name) {
110        Tag = item,
111        Checked = true
112      };
113      foreach (var child in item.Children)
114        node.Nodes.Add(CreateTreeNode(child));
115      return node;
116    }
117
118    private void UpdateComboBoxes() {
119      var selectedXAxis = (string)xAxisComboBox.SelectedItem;
120      var selectedYAxis = (string)yAxisComboBox.SelectedItem;
121      var selectedSizeAxis = (string)sizeComboBox.SelectedItem;
122      xAxisComboBox.Items.Clear();
123      yAxisComboBox.Items.Clear();
124      sizeComboBox.Items.Clear();
125
126      if (Content != null) {
127        var axisNames = GetAvailableKeys().ToArray();
128        var additionalAxisDimension = Enum.GetNames(typeof(AxisDimension));
129        var additionalSizeDimension = Enum.GetNames(typeof(SizeDimension));
130
131        xAxisComboBox.Items.AddRange(additionalAxisDimension);
132        xAxisComboBox.Items.AddRange(axisNames);
133        yAxisComboBox.Items.AddRange(additionalAxisDimension);
134        yAxisComboBox.Items.AddRange(axisNames);
135        sizeComboBox.Items.AddRange(additionalSizeDimension);
136        sizeComboBox.Items.AddRange(axisNames);
137        sizeComboBox.SelectedItem = SizeDimension.Constant.ToString();
138
139        bool changed = false;
140        if (selectedXAxis != null && xAxisComboBox.Items.Contains(selectedXAxis)) {
141          xAxisComboBox.SelectedItem = selectedXAxis;
142          changed = true;
143        }
144        if (selectedYAxis != null && yAxisComboBox.Items.Contains(selectedYAxis)) {
145          yAxisComboBox.SelectedItem = selectedYAxis;
146          changed = true;
147        }
148        if (selectedSizeAxis != null && sizeComboBox.Items.Contains(selectedSizeAxis)) {
149          sizeComboBox.SelectedItem = selectedSizeAxis;
150          changed = true;
151        }
152        if (changed) {
153          UpdateDataPoints();
154          //UpdateAxisLabels();
155        }
156      }
157    }
158
159    private void UpdateDataPoints() {
160      var series = chart.Series[0];
161      series.Points.Clear();
162      itemToIndexMapping.Clear();
163      categoricalMapping.Clear();
164      RebuildInverseIndex();
165
166      chart.ChartAreas[0].AxisX.IsMarginVisible = xAxisValue != AxisDimension.Index.ToString();
167      chart.ChartAreas[0].AxisY.IsMarginVisible = yAxisValue != AxisDimension.Index.ToString();
168
169      if (Content != null) {
170        var items = GetAvailableItems();
171        foreach (var item in items) {
172          var x = GetValue(item, xAxisValue);
173          var y = GetValue(item, yAxisValue);
174          var s = GetValue(item, sizeAxisValue);
175          if (x.HasValue && y.HasValue && s.HasValue) {
176            var dataPoint = new DataPoint(x.Value, new[] { y.Value, s.Value });
177            series.Points.Add(dataPoint);
178          }
179        }
180      }
181    }
182    private double? GetValue(RecursiveDataItem item, string key) {
183      if (item == null || string.IsNullOrEmpty(key))
184        return null;
185
186      if (Enum.IsDefined(typeof(AxisDimension), key)) {
187        var axisDimension = (AxisDimension)Enum.Parse(typeof(AxisDimension), key);
188        return GetValue(item, axisDimension);
189      } else if (Enum.IsDefined(typeof(SizeDimension), key)) {
190        var sizeDimension = (SizeDimension)Enum.Parse(typeof(SizeDimension), key);
191        return GetValue(item, sizeDimension);
192      } else if (item.Data.ContainsKey(key)) {
193        IItem value = item.Data[key];
194        var doubleValue = value as DoubleValue;
195        var intValue = value as IntValue;
196        var timeSpanValue = value as TimeSpanValue;
197        double? ret = null;
198        if (doubleValue != null) {
199          if (!double.IsNaN(doubleValue.Value) && !double.IsInfinity(doubleValue.Value))
200            ret = doubleValue.Value;
201        } else if (intValue != null)
202          ret = intValue.Value;
203        else if (timeSpanValue != null)
204          ret = timeSpanValue.Value.TotalSeconds;
205        else
206          ret = GetCategoricalValue(item, key, value.ToString());
207        return ret;
208      } else {
209        return null;
210      }
211    }
212    private double? GetCategoricalValue(RecursiveDataItem item, string key, string value) {
213      if (!categoricalMapping.ContainsKey(key)) {
214        categoricalMapping[key] = new Dictionary<object, double>();
215        var orderedCategories =
216          GetAvailableItems().Where(x => x.Data.ContainsKey(key)).Select(x => x.Data[key].ToString())
217            .Distinct().OrderBy(x => x, new NaturalStringComparer());
218        int count = 1;
219        foreach (var category in orderedCategories) {
220          categoricalMapping[key].Add(category, count);
221          count++;
222        }
223      }
224      if (!this.categoricalMapping[key].ContainsKey(value)) return null;
225      return this.categoricalMapping[key][value];
226    }
227    private double GetValue(RecursiveDataItem item, AxisDimension axisDimension) {
228      double value = double.NaN;
229      switch (axisDimension) {
230        case AxisDimension.Index:
231          value = itemToIndexMapping[item];
232          break;
233        default:
234          throw new ArgumentException("No handling strategy for " + axisDimension.ToString() + " is defined.");
235      }
236      return value;
237    }
238    private double GetValue(RecursiveDataItem item, SizeDimension sizeDimension) {
239      double value = double.NaN;
240      switch (sizeDimension) {
241        case SizeDimension.Constant:
242          value = 2;
243          break;
244        default:
245          throw new ArgumentException("No handling strategy for " + sizeDimension.ToString() + " is defined.");
246      }
247      return value;
248    }
249    private void RebuildInverseIndex() {
250      if (Content != null) {
251        itemToIndexMapping.Clear();
252        int i = 0;
253        foreach (var item in GetAvailableItems()) {
254          // ToDo: do not add if key (which one?) is not present within item
255          itemToIndexMapping.Add(item, i);
256          i++;
257        }
258      }
259    }
260    #endregion
261
262    #region Event Handlers
263    private void treeView_AfterCheck(object sender, TreeViewEventArgs e) {
264      UpdateComboBoxes();
265      UpdateDataPoints();
266    }
267
268    private void axisComboBox_SelectedValueChanged(object sender, EventArgs e) {
269      bool axisSelected = xAxisComboBox.SelectedIndex != -1 && yAxisComboBox.SelectedIndex != -1;
270
271      xAxisValue = (string)xAxisComboBox.SelectedItem;
272      yAxisValue = (string)yAxisComboBox.SelectedItem;
273      sizeAxisValue = (string)sizeComboBox.SelectedItem;
274
275      UpdateDataPoints();
276      //UpdateAxisLabels();
277    }
278    #endregion
279  }
280}
Note: See TracBrowser for help on using the repository browser.