Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 14778 was 14388, checked in by pfleck, 8 years ago

#2698

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