Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.DataPreprocessing.Views/3.4/ScatterPlotMultiView.cs @ 14384

Last change on this file since 14384 was 14384, checked in by pfleck, 7 years ago

#2698 Implemented unchecking of variables in multi-scatterplot.

File size: 14.2 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Drawing;
4using System.Linq;
5using System.Windows.Forms;
6using HeuristicLab.Analysis;
7using HeuristicLab.Collections;
8using HeuristicLab.Common;
9using HeuristicLab.Core.Views;
10using HeuristicLab.Data;
11using HeuristicLab.MainForm;
12using HeuristicLab.MainForm.WindowsForms;
13
14namespace HeuristicLab.DataPreprocessing.Views {
15  [View("Scatter Plot Multi View")]
16  [Content(typeof(ScatterPlotContent), false)]
17  public partial class ScatterPlotMultiView : PreprocessingCheckedVariablesView {
18    private const int MaxAutoSizeElements = 6;
19    private const int FixedChartWidth = 250;
20    private const int FixedChartHeight = 150;
21
22    private readonly IDictionary<string, Label> columnHeaderCache;
23    private readonly IDictionary<string, Label> rowHeaderCache;
24    private readonly IDictionary<Tuple<string/*col*/, string/*row*/>, ItemView> bodyCache;
25
26    public ScatterPlotMultiView() {
27      InitializeComponent();
28
29      columnHeaderScrollPanel.HorizontalScroll.Enabled = true;
30      columnHeaderScrollPanel.VerticalScroll.Enabled = false;
31      columnHeaderScrollPanel.HorizontalScroll.Visible = false;
32      columnHeaderScrollPanel.VerticalScroll.Visible = false;
33
34      rowHeaderScrollPanel.HorizontalScroll.Enabled = false;
35      rowHeaderScrollPanel.VerticalScroll.Enabled = true;
36      rowHeaderScrollPanel.HorizontalScroll.Visible = false;
37      rowHeaderScrollPanel.VerticalScroll.Visible = false;
38
39      bodyScrollPanel.HorizontalScroll.Enabled = true;
40      bodyScrollPanel.VerticalScroll.Enabled = true;
41      bodyScrollPanel.HorizontalScroll.Visible = true;
42      bodyScrollPanel.VerticalScroll.Visible = true;
43      bodyScrollPanel.AutoScroll = true;
44
45      columnHeaderCache = new Dictionary<string, Label>();
46      rowHeaderCache = new Dictionary<string, Label>();
47      bodyCache = new Dictionary<Tuple<string, string>, ItemView>();
48
49      bodyScrollPanel.MouseWheel += bodyScrollPanel_MouseWheel;
50    }
51
52    public new ScatterPlotContent Content {
53      get { return (ScatterPlotContent)base.Content; }
54      set { base.Content = value; }
55    }
56
57    protected override void OnContentChanged() {
58      base.OnContentChanged();
59      if (Content != null) {
60        GenerateCharts();
61      }
62    }
63
64    protected override void CheckedItemsChanged(object sender, CollectionItemsChangedEventArgs<IndexedItem<StringValue>> checkedItems) {
65      base.CheckedItemsChanged(sender, checkedItems);
66      foreach (var variable in checkedItems.Items.Select(i => i.Value.Value)) {
67        if (IsVariableChecked(variable))
68          AddChartToTable(variable);
69        else
70          RemoveChartFromTable(variable);
71      }
72    }
73
74    private void AddChartToTable(string variable) {
75
76    }
77    // remove from headers and body and shift remaining slots to fill the gap
78    private void RemoveChartFromTable(string variable) {
79      frameTableLayoutPanel.SuspendLayout();
80
81      // remove column header
82      var colH = columnHeaderTableLayoutPanel;
83      int colIdx = colH.GetColumn(colH.Controls[variable]);
84      RemoveColumnHelper(colH, colIdx);
85
86      // remove row header
87      var rowH = rowHeaderTableLayoutPanel;
88      int rowIdx = rowH.GetRow(rowH.Controls[variable]);
89      RemoveRowHelper(rowH, rowIdx);
90
91      // remove from body
92      var body = bodyTableLayoutPanel;
93      RemoveColumnHelper(body, colIdx);
94      RemoveRowHelper(body, rowIdx);
95
96      frameTableLayoutPanel.ResumeLayout(true);
97    }
98
99    private void RemoveColumnHelper(TableLayoutPanel tlp, int idx) {
100      for (int r = 0; r < tlp.RowCount; r++)
101        tlp.Controls.Remove(tlp.GetControlFromPosition(idx, r));
102      for (int c = idx + 1; c < tlp.ColumnCount; c++) {
103        for (int r = 0; r < tlp.RowCount; r++) {
104          var control = tlp.GetControlFromPosition(c, r);
105          if (control != null) {
106            tlp.SetColumn(control, c - 1);
107          }
108        }
109      }
110      tlp.ColumnStyles.RemoveAt(tlp.ColumnCount - 1);
111      tlp.ColumnCount--;
112    }
113    private void RemoveRowHelper(TableLayoutPanel tlp, int idx) {
114      for (int c = 0; c < tlp.ColumnCount; c++)
115        tlp.Controls.Remove(tlp.GetControlFromPosition(c, idx));
116      for (int r = idx + 1; r < tlp.RowCount; r++) {
117        for (int c = 0; c < tlp.ColumnCount; c++) {
118          var control = tlp.GetControlFromPosition(c, r);
119          if (control != null) {
120            tlp.SetRow(control, r - 1);
121          }
122        }
123      }
124      tlp.RowStyles.RemoveAt(tlp.RowCount - 1);
125      tlp.RowCount--;
126    }
127
128    #region Add/Remove/Update Variable, Reset
129    protected override void AddVariable(string name) {
130      base.AddVariable(name);
131    }
132
133    protected override void RemoveVariable(string name) {
134      base.RemoveVariable(name);
135
136      // clear caches
137      columnHeaderCache.Remove(name);
138      rowHeaderCache.Remove(name);
139      var keys = bodyCache.Keys.Where(t => t.Item1 == name || t.Item2 == name).ToList();
140      foreach (var key in keys)
141        bodyCache.Remove(key);
142
143      if (IsVariableChecked(name)) {
144        RemoveChartFromTable(name);
145      }
146    }
147    protected override void UpdateVariable(string name) {
148      base.UpdateVariable(name);
149    }
150    protected override void ResetAllVariables() {
151      GenerateCharts();
152    }
153    #endregion
154
155
156    #region Creating Header and Body
157    private Label GetColumnHeader(string variable) {
158      if (!columnHeaderCache.ContainsKey(variable)) {
159        columnHeaderCache.Add(variable, new Label() {
160          Text = variable,
161          TextAlign = ContentAlignment.MiddleCenter,
162          Name = variable,
163          Height = columnHeaderTableLayoutPanel.Height,
164          Dock = DockStyle.Fill,
165          Margin = new Padding(3)
166        });
167      }
168      return columnHeaderCache[variable];
169    }
170    private Label GetRowHeader(string variable) {
171      if (!rowHeaderCache.ContainsKey(variable)) {
172        rowHeaderCache.Add(variable, new Label() {
173          Text = variable,
174          TextAlign = ContentAlignment.MiddleCenter,
175          Name = variable,
176          Width = rowHeaderTableLayoutPanel.Width,
177          Dock = DockStyle.Fill,
178          Margin = new Padding(3)
179        });
180      }
181      return rowHeaderCache[variable];
182    }
183    private ItemView GetBody(string colVariable, string rowVariable) {
184      var key = Tuple.Create(colVariable, rowVariable);
185      if (!bodyCache.ContainsKey(key)) {
186        if (rowVariable == colVariable) { // use historgram if x and y variable are equal
187          PreprocessingDataTable dataTable = new PreprocessingDataTable();
188          DataRow dataRow = Content.CreateDataRow(rowVariable, DataRowVisualProperties.DataRowChartType.Histogram);
189          dataTable.Rows.Add(dataRow);
190          PreprocessingDataTableView pcv = new PreprocessingDataTableView {
191            Name = key.ToString(),
192            Content = dataTable,
193            Dock = DockStyle.Fill,
194            ShowLegend = false,
195            XAxisFormat = "G3"
196          };
197          pcv.ChartDoubleClick += HistogramDoubleClick;
198          bodyCache.Add(key, pcv);
199        } else { //scatter plot
200          ScatterPlot scatterPlot = Content.CreateScatterPlot(colVariable, rowVariable);
201          PreprocessingScatterPlotView pspv = new PreprocessingScatterPlotView {
202            Name = key.ToString(),
203            Content = scatterPlot,
204            Dock = DockStyle.Fill,
205            ShowLegend = false,
206            XAxisFormat = "G3"
207          };
208          pspv.ChartDoubleClick += ScatterPlotDoubleClick;
209          bodyCache.Add(key, pspv);
210        }
211      }
212      return bodyCache[key];
213    }
214    #endregion
215
216
217
218
219    #region Generate Charts
220    private void GenerateCharts() {
221      var variables = GetCheckedVariables();
222
223      // Clear old layouts and cache
224      foreach (var tableLayoutPanel in new[] { columnHeaderTableLayoutPanel, rowHeaderTableLayoutPanel, bodyTableLayoutPanel }) {
225        tableLayoutPanel.Controls.Clear();
226        tableLayoutPanel.ColumnStyles.Clear();
227        tableLayoutPanel.RowStyles.Clear();
228      }
229      columnHeaderCache.Clear();
230      rowHeaderCache.Clear();
231      bodyCache.Clear();
232
233      // Set row and column count
234      columnHeaderTableLayoutPanel.ColumnCount = variables.Count;
235      rowHeaderTableLayoutPanel.RowCount = variables.Count;
236      bodyTableLayoutPanel.ColumnCount = variables.Count;
237      bodyTableLayoutPanel.RowCount = variables.Count;
238
239      // Set column and row layout
240      int width = variables.Count <= MaxAutoSizeElements ? bodyTableLayoutPanel.Width / variables.Count : FixedChartWidth;
241      int height = variables.Count <= MaxAutoSizeElements ? bodyTableLayoutPanel.Height / variables.Count : FixedChartHeight;
242      for (int i = 0; i < variables.Count; i++) {
243        columnHeaderTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, width));
244        rowHeaderTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, height));
245        bodyTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, width));
246        bodyTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, height));
247      }
248
249      frameTableLayoutPanel.SuspendLayout();
250      AddHeaderToTableLayoutPanels();
251      AddChartsToTableLayoutPanel();
252      UpdateHeaderMargin();
253      frameTableLayoutPanel.ResumeLayout(true);
254    }
255
256    private void AddHeaderToTableLayoutPanels() {
257      int i = 0;
258      foreach (var variable in GetCheckedVariables()) {
259        columnHeaderTableLayoutPanel.Controls.Add(GetColumnHeader(variable), i, 0);
260        rowHeaderTableLayoutPanel.Controls.Add(GetRowHeader(variable), 0, i);
261        i++;
262      }
263    }
264    private void AddChartsToTableLayoutPanel() {
265      int c = 0;
266      foreach (var colVar in GetCheckedVariables()) {
267        if (!IsVariableChecked(colVar)) continue;
268        int r = 0;
269        foreach (var rowVar in GetCheckedVariables()) {
270          if (!IsVariableChecked(rowVar)) continue;
271          bodyTableLayoutPanel.Controls.Add(GetBody(colVar, rowVar), c, r);
272          r++;
273        }
274        c++;
275      }
276    }
277
278    #endregion
279
280    #region DoubleClick Events
281    //Open scatter plot in new tab with new content when double clicked
282    private void ScatterPlotDoubleClick(object sender, EventArgs e) {
283      PreprocessingScatterPlotView pspv = (PreprocessingScatterPlotView)sender;
284      ScatterPlotContent scatterContent = new ScatterPlotContent(Content, new Cloner());  // create new content
285      ScatterPlot scatterPlot = pspv.Content;
286
287      //Extract variable names from scatter plot and set them in content
288      if (scatterPlot.Rows.Count == 1) {
289        string[] variables = scatterPlot.Rows.ElementAt(0).Name.Split(new string[] { " - " }, StringSplitOptions.None); // extract variable names from string
290        scatterContent.SelectedXVariable = variables[0];
291        scatterContent.SelectedYVariable = variables[1];
292      }
293
294      MainFormManager.MainForm.ShowContent(scatterContent, typeof(ScatterPlotSingleView));  // open in new tab
295    }
296
297    //open histogram in new tab with new content when double clicked
298    private void HistogramDoubleClick(object sender, EventArgs e) {
299      PreprocessingDataTableView pcv = (PreprocessingDataTableView)sender;
300      HistogramContent histoContent = new HistogramContent(Content.PreprocessingData);  // create new content     
301      histoContent.VariableItemList = Content.CreateVariableItemList();
302      PreprocessingDataTable dataTable = pcv.Content;
303
304      //Set variable item list from with variable from data table
305      if (dataTable.Rows.Count == 1) { // only one data row should be in data table
306        string variableName = dataTable.Rows.ElementAt(0).Name;
307
308        // set only variable name checked
309        foreach (var checkedItem in histoContent.VariableItemList) {
310          histoContent.VariableItemList.SetItemCheckedState(checkedItem, checkedItem.Value == variableName);
311        }
312      }
313      MainFormManager.MainForm.ShowContent(histoContent, typeof(HistogramView));  // open in new tab
314    }
315    #endregion
316
317    private void bodyScrollPanel_Scroll(object sender, ScrollEventArgs e) {
318      SyncScroll();
319
320      UpdateHeaderMargin();
321    }
322    private void bodyScrollPanel_MouseWheel(object sender, MouseEventArgs e) {
323      // Scrolling with the mouse wheel is not captured in the Scoll event
324      SyncScroll();
325    }
326    private void SyncScroll() {
327      //Debug.WriteLine("H: {0} <- {1}", columnHeaderScrollPanel.HorizontalScroll.Value, bodyScrollPanel.HorizontalScroll.Value);
328      //Debug.WriteLine("V: {0} <- {1}", rowScrollLayoutPanel.VerticalScroll.Value, bodyScrollPanel.VerticalScroll.Value);
329
330      frameTableLayoutPanel.SuspendRepaint();
331
332      columnHeaderScrollPanel.HorizontalScroll.Minimum = bodyScrollPanel.HorizontalScroll.Minimum;
333      columnHeaderScrollPanel.HorizontalScroll.Maximum = bodyScrollPanel.HorizontalScroll.Maximum;
334      rowHeaderScrollPanel.VerticalScroll.Minimum = bodyScrollPanel.VerticalScroll.Minimum;
335      rowHeaderScrollPanel.VerticalScroll.Maximum = bodyScrollPanel.VerticalScroll.Maximum;
336
337      columnHeaderScrollPanel.HorizontalScroll.Value = Math.Max(bodyScrollPanel.HorizontalScroll.Value, 1);
338      rowHeaderScrollPanel.VerticalScroll.Value = Math.Max(bodyScrollPanel.VerticalScroll.Value, 1);
339      // minimum 1 is nececary  because of two factors:
340      // - setting the Value-property of Horizontal/VerticalScroll updates the internal state but the Value-property stays 0
341      // - setting the same number of the Value-property has no effect
342      // since the Value-property is always 0, setting it to 0 would have no effect; so it is set to 1 instead
343
344      frameTableLayoutPanel.ResumeRepaint(true);
345    }
346
347    // add a margin to the header table layouts if the scollbar is visible to account for the width/height of the scrollbar
348    private void UpdateHeaderMargin() {
349      columnHeaderScrollPanel.Margin = new Padding(0, 0, bodyScrollPanel.VerticalScroll.Visible ? SystemInformation.VerticalScrollBarWidth : 0, 0);
350      rowHeaderScrollPanel.Margin = new Padding(0, 0, 0, bodyScrollPanel.HorizontalScroll.Visible ? SystemInformation.HorizontalScrollBarHeight : 0);
351    }
352  }
353}
Note: See TracBrowser for help on using the repository browser.