source: trunk/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionVariableImpactsView.cs @ 15752

Last change on this file since 15752 was 15752, checked in by fholzing, 2 years ago

#2871: Changed back to Task, abort Thread if any other View is shown

File size: 8.7 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2018 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.Threading;
26using System.Threading.Tasks;
27using HeuristicLab.Common;
28using HeuristicLab.Data;
29using HeuristicLab.MainForm;
30
31namespace HeuristicLab.Problems.DataAnalysis.Views {
32  [View("Variable Impacts")]
33  [Content(typeof(IRegressionSolution))]
34  public partial class RegressionSolutionVariableImpactsView : DataAnalysisSolutionEvaluationView {
35    #region Nested Types
36    private enum SortingCriteria {
37      ImpactValue,
38      Occurrence,
39      VariableName
40    }
41    #endregion
42
43    #region Fields
44    private Dictionary<string, double> rawVariableImpacts = new Dictionary<string, double>();
45    private Thread thread;
46    #endregion
47
48    #region Getter/Setter
49    public new IRegressionSolution Content {
50      get { return (IRegressionSolution)base.Content; }
51      set {
52        base.Content = value;
53      }
54    }
55    #endregion
56
57    #region Ctor
58    public RegressionSolutionVariableImpactsView()
59      : base() {
60      InitializeComponent();
61
62      //Little workaround. If you fill the ComboBox-Items in the other partial class, the UI-Designer will moan.
63      this.sortByComboBox.Items.AddRange(Enum.GetValues(typeof(SortingCriteria)).Cast<object>().ToArray());
64      this.sortByComboBox.SelectedItem = SortingCriteria.ImpactValue;
65
66      //Set the default values
67      this.dataPartitionComboBox.SelectedIndex = 0;
68      this.replacementComboBox.SelectedIndex = 0;
69      this.factorVarReplComboBox.SelectedIndex = 0;
70    }
71    #endregion
72
73    #region Events
74    protected override void RegisterContentEvents() {
75      base.RegisterContentEvents();
76      Content.ModelChanged += new EventHandler(Content_ModelChanged);
77      Content.ProblemDataChanged += new EventHandler(Content_ProblemDataChanged);
78    }
79
80    protected override void DeregisterContentEvents() {
81      base.DeregisterContentEvents();
82      Content.ModelChanged -= new EventHandler(Content_ModelChanged);
83      Content.ProblemDataChanged -= new EventHandler(Content_ProblemDataChanged);
84    }
85
86    protected virtual void Content_ProblemDataChanged(object sender, EventArgs e) {
87      OnContentChanged();
88    }
89
90    protected virtual void Content_ModelChanged(object sender, EventArgs e) {
91      OnContentChanged();
92    }
93
94    protected override void OnContentChanged() {
95      base.OnContentChanged();
96      if (Content == null) {
97        variableImactsArrayView.Content = null;
98      } else {
99        UpdateVariableImpact();
100      }
101    }
102
103    private void RegressionSolutionVariableImpactsView_VisibleChanged(object sender, EventArgs e) {
104      if (thread == null) { return; }
105
106      if (thread.IsAlive) { thread.Abort(); }
107      thread = null;
108    }
109
110
111    private void dataPartitionComboBox_SelectedIndexChanged(object sender, EventArgs e) {
112      UpdateVariableImpact();
113    }
114
115    private void replacementComboBox_SelectedIndexChanged(object sender, EventArgs e) {
116      UpdateVariableImpact();
117    }
118
119    private void sortByComboBox_SelectedIndexChanged(object sender, EventArgs e) {
120      //Update the default ordering (asc,desc), but remove the eventHandler beforehand (otherwise the data would be ordered twice)
121      ascendingCheckBox.CheckedChanged -= ascendingCheckBox_CheckedChanged;
122      switch ((SortingCriteria)sortByComboBox.SelectedItem) {
123        case SortingCriteria.ImpactValue:
124          ascendingCheckBox.Checked = false;
125          break;
126        case SortingCriteria.Occurrence:
127          ascendingCheckBox.Checked = true;
128          break;
129        case SortingCriteria.VariableName:
130          ascendingCheckBox.Checked = true;
131          break;
132        default:
133          throw new NotImplementedException("Ordering for selected SortingCriteria not implemented");
134      }
135      ascendingCheckBox.CheckedChanged += ascendingCheckBox_CheckedChanged;
136
137      UpdateDataOrdering();
138    }
139
140    private void ascendingCheckBox_CheckedChanged(object sender, EventArgs e) {
141      UpdateDataOrdering();
142    }
143
144    #endregion
145
146    #region Helper Methods   
147    private void UpdateVariableImpact() {
148      //Check if the selection is valid
149      if (Content == null) { return; }
150      if (replacementComboBox.SelectedIndex < 0) { return; }
151      if (dataPartitionComboBox.SelectedIndex < 0) { return; }
152      if (factorVarReplComboBox.SelectedIndex < 0) { return; }
153
154      //Prepare arguments
155      var mainForm = (MainForm.WindowsForms.MainForm)MainFormManager.MainForm;
156      var replMethod = (RegressionSolutionVariableImpactsCalculator.ReplacementMethodEnum)replacementComboBox.Items[replacementComboBox.SelectedIndex];
157      var factorReplMethod = (RegressionSolutionVariableImpactsCalculator.FactorReplacementMethodEnum)factorVarReplComboBox.Items[factorVarReplComboBox.SelectedIndex];
158      var dataPartition = (RegressionSolutionVariableImpactsCalculator.DataPartitionEnum)dataPartitionComboBox.SelectedItem;
159
160      variableImactsArrayView.Caption = Content.Name + " Variable Impacts";
161
162      mainForm.AddOperationProgressToView(this, "Calculating variable impacts for " + Content.Name);
163
164      Task.Factory.StartNew(() => {
165        thread = Thread.CurrentThread;
166        //Remember the original ordering of the variables
167        var impacts = RegressionSolutionVariableImpactsCalculator.CalculateImpacts(Content, dataPartition, replMethod, factorReplMethod);
168        var problemData = Content.ProblemData;
169        var inputvariables = new HashSet<string>(problemData.AllowedInputVariables.Union(Content.Model.VariablesUsedForPrediction));
170        var originalVariableOrdering = problemData.Dataset.VariableNames.Where(v => inputvariables.Contains(v)).Where(problemData.Dataset.VariableHasType<double>).ToList();
171
172        rawVariableImpacts.Clear();
173        originalVariableOrdering.ForEach(v => rawVariableImpacts.Add(v, impacts.First(vv => vv.Item1 == v).Item2));
174      }).ContinueWith((o) => {
175        UpdateDataOrdering();
176        mainForm.RemoveOperationProgressFromView(this);
177        thread = null;
178      }, TaskScheduler.FromCurrentSynchronizationContext());
179    }
180
181    /// <summary>
182    /// Updates the <see cref="variableImactsArrayView"/> according to the selected ordering <see cref="ascendingCheckBox"/> of the selected Column <see cref="sortByComboBox"/>
183    /// The default is "Descending" by "VariableImpact" (as in previous versions)
184    /// </summary>
185    private void UpdateDataOrdering() {
186      //Check if valid sortingCriteria is selected and data exists
187      if (sortByComboBox.SelectedIndex == -1) { return; }
188      if (rawVariableImpacts == null) { return; }
189      if (!rawVariableImpacts.Any()) { return; }
190
191      var selectedItem = (SortingCriteria)sortByComboBox.SelectedItem;
192      bool ascending = ascendingCheckBox.Checked;
193
194      IEnumerable<KeyValuePair<string, double>> orderedEntries = null;
195
196      //Sort accordingly
197      switch (selectedItem) {
198        case SortingCriteria.ImpactValue:
199          orderedEntries = rawVariableImpacts.OrderBy(v => v.Value);
200          break;
201        case SortingCriteria.Occurrence:
202          orderedEntries = rawVariableImpacts;
203          break;
204        case SortingCriteria.VariableName:
205          orderedEntries = rawVariableImpacts.OrderBy(v => v.Key, new NaturalStringComparer());
206          break;
207        default:
208          throw new NotImplementedException("Ordering for selected SortingCriteria not implemented");
209      }
210
211      if (!ascending) { orderedEntries = orderedEntries.Reverse(); }
212
213      //Write the data back
214      var impactArray = new DoubleArray(orderedEntries.Select(i => i.Value).ToArray()) {
215        ElementNames = orderedEntries.Select(i => i.Key)
216      };
217
218      //Could be, if the View was closed
219      if (!variableImactsArrayView.IsDisposed) {
220        variableImactsArrayView.Content = (DoubleArray)impactArray.AsReadOnly();
221      }
222    }
223    #endregion
224  }
225}
Note: See TracBrowser for help on using the repository browser.