Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionPartialDependencePlotView.cs @ 15583

Last change on this file since 15583 was 15583, checked in by swagner, 6 years ago

#2640: Updated year of copyrights in license headers

File size: 22.6 KB
RevLine 
[13817]1#region License Information
2/* HeuristicLab
[15583]3 * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[13817]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
[13828]22using System;
[14826]23using System.Collections;
[13817]24using System.Collections.Generic;
[13850]25using System.Drawing;
[14267]26using System.Globalization;
[13808]27using System.Linq;
[13843]28using System.Threading.Tasks;
[13808]29using System.Windows.Forms;
30using HeuristicLab.Common;
31using HeuristicLab.MainForm;
[13843]32using HeuristicLab.Visualization.ChartControlsExtensions;
[13808]33
34namespace HeuristicLab.Problems.DataAnalysis.Views {
[14852]35  [View("Partial Dependence Plots")]
[13808]36  [Content(typeof(IRegressionSolution))]
[14852]37  public partial class RegressionSolutionPartialDependencePlotView : DataAnalysisSolutionEvaluationView {
38    private readonly Dictionary<string, IPartialDependencePlot> partialDependencePlots;
[13850]39    private readonly Dictionary<string, DensityChart> densityCharts;
40    private readonly Dictionary<string, Panel> groupingPanels;
[14267]41    private ModifiableDataset sharedFixedVariables;
[13850]42
[13831]43    private const int Points = 200;
[13995]44    private int MaxColumns = 4;
[13808]45
[13850]46    private IEnumerable<string> VisibleVariables {
47      get {
48        foreach (ListViewItem item in variableListView.CheckedItems)
49          yield return item.Text;
50      }
[13843]51    }
[14852]52    private IEnumerable<IPartialDependencePlot> VisiblePartialDependencePlots {
53      get { return VisibleVariables.Select(v => partialDependencePlots[v]); }
[13850]54    }
55    private IEnumerable<DensityChart> VisibleDensityCharts {
56      get { return VisibleVariables.Select(v => densityCharts[v]); }
57    }
58    private IEnumerable<Panel> VisibleChartsPanels {
59      get { return VisibleVariables.Select(v => groupingPanels[v]); }
60    }
[13843]61
[14852]62    public RegressionSolutionPartialDependencePlotView() {
[13808]63      InitializeComponent();
[14852]64      partialDependencePlots = new Dictionary<string, IPartialDependencePlot>();
[13850]65      densityCharts = new Dictionary<string, DensityChart>();
66      groupingPanels = new Dictionary<string, Panel>();
[13846]67
68      limitView.Content = new DoubleLimit(0, 1);
[14021]69      limitView.Content.ValueChanged += limit_ValueChanged;
[13850]70
[14021]71      densityComboBox.SelectedIndex = 1; // select Training
72
[13850]73      // Avoid additional horizontal scrollbar
74      var vertScrollWidth = SystemInformation.VerticalScrollBarWidth;
75      scrollPanel.Padding = new Padding(0, 0, vertScrollWidth, 0);
76      scrollPanel.AutoScroll = true;
[13808]77    }
78
79    public new IRegressionSolution Content {
80      get { return (IRegressionSolution)base.Content; }
[13831]81      set { base.Content = value; }
[13808]82    }
83
84    protected override void RegisterContentEvents() {
85      base.RegisterContentEvents();
[13995]86      Content.ModelChanged += solution_ModelChanged;
[13808]87    }
88
89    protected override void DeregisterContentEvents() {
[13995]90      Content.ModelChanged -= solution_ModelChanged;
[13808]91      base.DeregisterContentEvents();
92    }
93
94    protected override void OnContentChanged() {
95      base.OnContentChanged();
[13817]96      if (Content == null) return;
[13831]97      var problemData = Content.ProblemData;
[13846]98
99      // Init Y-axis range
100      double min = double.MaxValue, max = double.MinValue;
101      var trainingTarget = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices);
102      foreach (var t in trainingTarget) {
103        if (t < min) min = t;
104        if (t > max) max = t;
105      }
106      double range = max - min;
107      const double scale = 1.0 / 3.0;
108      double axisMin, axisMax, axisInterval;
109      ChartUtil.CalculateAxisInterval(min - scale * range, max + scale * range, 5, out axisMin, out axisMax, out axisInterval);
110      automaticYAxisCheckBox.Checked = false;
111      limitView.ReadOnly = false;
112      limitView.Content.Lower = axisMin;
113      limitView.Content.Upper = axisMax;
114
[14464]115      // create dataset of problemData input variables and model input variables
116      // necessary workaround to have the variables in the occuring order
117      var inputvariables =
118        new HashSet<string>(Content.ProblemData.AllowedInputVariables.Union(Content.Model.VariablesUsedForPrediction));
119      var allowedInputVariables =
120        Content.ProblemData.Dataset.VariableNames.Where(v => inputvariables.Contains(v)).ToList();
121
122
[14826]123      var doubleVariables = allowedInputVariables.Where(problemData.Dataset.VariableHasType<double>);
124      var doubleVariableValues = (IEnumerable<IList>)doubleVariables.Select(x => new List<double> { problemData.Dataset.GetDoubleValues(x, problemData.TrainingIndices).Median() });
125
126      var factorVariables = allowedInputVariables.Where(problemData.Dataset.VariableHasType<string>);
127      var factorVariableValues = (IEnumerable<IList>)factorVariables.Select(x => new List<string> {
128        problemData.Dataset.GetStringValues(x, problemData.TrainingIndices)
129        .GroupBy(val => val).OrderByDescending(g => g.Count()).First().Key // most frequent value
130      });
131
[14267]132      if (sharedFixedVariables != null)
[14307]133        sharedFixedVariables.ItemChanged -= SharedFixedVariables_ItemChanged;
[13850]134
[14826]135      sharedFixedVariables = new ModifiableDataset(doubleVariables.Concat(factorVariables), doubleVariableValues.Concat(factorVariableValues));
136
137
[13850]138      // create controls
[14852]139      partialDependencePlots.Clear();
[13850]140      densityCharts.Clear();
141      groupingPanels.Clear();
[14826]142      foreach (var variableName in doubleVariables) {
[14852]143        var plot = CreatePartialDependencePlot(variableName, sharedFixedVariables);
144        partialDependencePlots.Add(variableName, plot);
[13850]145
146        var densityChart = new DensityChart() {
147          Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right,
148          Margin = Padding.Empty,
149          Height = 12,
[14131]150          Visible = false,
[14852]151          Top = (int)(plot.Height * 0.1),
[13850]152        };
153        densityCharts.Add(variableName, densityChart);
154
[14852]155        plot.ZoomChanged += (o, e) => {
156          var pdp = (PartialDependencePlot)o;
157          var density = densityCharts[pdp.FreeVariable];
158          density.Visible = densityComboBox.SelectedIndex != 0 && !pdp.IsZoomed;
[14089]159          if (density.Visible)
[14852]160            UpdateDensityChart(density, pdp.FreeVariable);
[14089]161        };
[14852]162        plot.SizeChanged += (o, e) => {
163          var pdp = (PartialDependencePlot)o;
164          var density = densityCharts[pdp.FreeVariable];
165          density.Top = (int)(pdp.Height * 0.1);
[14131]166        };
[14089]167
[14158]168        // Initially, the inner plot areas are not initialized for hidden charts (scollpanel, ...)
169        // This event handler listens for the paint event once (where everything is already initialized) to do some manual layouting.
[14852]170        plot.ChartPostPaint += OnPartialDependencePlotPostPaint;
[14158]171
[13850]172        var panel = new Panel() {
[13820]173          Dock = DockStyle.Fill,
174          Margin = Padding.Empty,
[13850]175          BackColor = Color.White
[13820]176        };
[13843]177
[13850]178        panel.Controls.Add(densityChart);
[14852]179        panel.Controls.Add(plot);
[13850]180        groupingPanels.Add(variableName, panel);
[13808]181      }
[14826]182      foreach (var variableName in factorVariables) {
[14852]183        var plot = CreateFactorPartialDependencePlot(variableName, sharedFixedVariables);
184        partialDependencePlots.Add(variableName, plot);
[13850]185
[14826]186        var densityChart = new DensityChart() {
187          Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right,
188          Margin = Padding.Empty,
189          Height = 12,
190          Visible = false,
[14852]191          Top = (int)(plot.Height * 0.1),
[14826]192        };
193        densityCharts.Add(variableName, densityChart);
[14852]194        plot.ZoomChanged += (o, e) => {
195          var pdp = (FactorPartialDependencePlot)o;
196          var density = densityCharts[pdp.FreeVariable];
197          density.Visible = densityComboBox.SelectedIndex != 0 && !pdp.IsZoomed;
[14826]198          if (density.Visible)
[14852]199            UpdateDensityChart(density, pdp.FreeVariable);
[14826]200        };
[14852]201        plot.SizeChanged += (o, e) => {
202          var pdp = (FactorPartialDependencePlot)o;
203          var density = densityCharts[pdp.FreeVariable];
204          density.Top = (int)(pdp.Height * 0.1);
[14826]205        };
206
207        // Initially, the inner plot areas are not initialized for hidden charts (scollpanel, ...)
208        // This event handler listens for the paint event once (where everything is already initialized) to do some manual layouting.
[14852]209        plot.ChartPostPaint += OnFactorPartialDependencePlotPostPaint;
[14826]210
211        var panel = new Panel() {
212          Dock = DockStyle.Fill,
213          Margin = Padding.Empty,
214          BackColor = Color.White
215        };
216
217        panel.Controls.Add(densityChart);
[14852]218        panel.Controls.Add(plot);
[14826]219        groupingPanels.Add(variableName, panel);
220      }
[13828]221      // update variable list
[14021]222      variableListView.ItemChecked -= variableListView_ItemChecked;
[13828]223      variableListView.Items.Clear();
[13845]224      foreach (var variable in allowedInputVariables)
225        variableListView.Items.Add(key: variable, text: variable, imageIndex: 0);
226
[13948]227      foreach (var variable in Content.Model.VariablesUsedForPrediction)
[13845]228        variableListView.Items[variable].Checked = true;
[14021]229      variableListView.ItemChecked += variableListView_ItemChecked;
230
[14267]231      sharedFixedVariables.ItemChanged += SharedFixedVariables_ItemChanged;
232
[14021]233      RecalculateAndRelayoutCharts();
[13808]234    }
[14021]235
[14267]236    private void SharedFixedVariables_ItemChanged(object sender, EventArgs<int, int> e) {
237      double yValue = Content.Model.GetEstimatedValues(sharedFixedVariables, new[] { 0 }).Single();
238      string title = Content.ProblemData.TargetVariable + ": " + yValue.ToString("G5", CultureInfo.CurrentCulture);
[14852]239      foreach (var chart in partialDependencePlots.Values) {
[14267]240        if (!string.IsNullOrEmpty(chart.YAxisTitle)) { // only show title for first column in grid
241          chart.YAxisTitle = title;
242        }
243      }
244    }
245
[14826]246
[14852]247    private void OnPartialDependencePlotPostPaint(object o, EventArgs e) {
248      var plot = (PartialDependencePlot)o;
249      var density = densityCharts[plot.FreeVariable];
[14158]250
[14852]251      density.Width = plot.Width;
[14158]252
[14852]253      var gcPlotPosition = plot.InnerPlotPosition;
254      density.Left = (int)(gcPlotPosition.X / 100.0 * plot.Width);
255      density.Width = (int)(gcPlotPosition.Width / 100.0 * plot.Width);
256      plot.UpdateTitlePosition();
[14158]257
258      // removed after succesful layouting due to performance reasons
259      if (gcPlotPosition.Width != 0)
[14852]260        plot.ChartPostPaint -= OnPartialDependencePlotPostPaint;
[14158]261    }
262
[14852]263    private void OnFactorPartialDependencePlotPostPaint(object o, EventArgs e) {
264      var plot = (FactorPartialDependencePlot)o;
265      var density = densityCharts[plot.FreeVariable];
[14826]266
[14852]267      density.Width = plot.Width;
[14826]268
[14852]269      var gcPlotPosition = plot.InnerPlotPosition;
270      density.Left = (int)(gcPlotPosition.X / 100.0 * plot.Width);
271      density.Width = (int)(gcPlotPosition.Width / 100.0 * plot.Width);
272      plot.UpdateTitlePosition();
[14826]273
274      // removed after succesful layouting due to performance reasons
275      if (gcPlotPosition.Width != 0)
[14852]276        plot.ChartPostPaint -= OnFactorPartialDependencePlotPostPaint;
[14826]277    }
278
[14021]279    private async void RecalculateAndRelayoutCharts() {
280      foreach (var variable in VisibleVariables) {
[14852]281        var plot = partialDependencePlots[variable];
282        await plot.RecalculateAsync(false, false);
[14021]283      }
[14852]284      partialDependencePlotTableLayout.SuspendLayout();
[14021]285      SetupYAxis();
286      ReOrderControls();
287      SetStyles();
[14852]288      partialDependencePlotTableLayout.ResumeLayout();
289      partialDependencePlotTableLayout.Refresh();
[14021]290      foreach (var variable in VisibleVariables) {
[14826]291        DensityChart densityChart;
292        if (densityCharts.TryGetValue(variable, out densityChart)) {
293          UpdateDensityChart(densityChart, variable);
294        }
[14021]295      }
296    }
[14852]297    private PartialDependencePlot CreatePartialDependencePlot(string variableName, ModifiableDataset sharedFixedVariables) {
298      var plot = new PartialDependencePlot {
[13850]299        Dock = DockStyle.Fill,
300        Margin = Padding.Empty,
301        ShowLegend = false,
302        ShowCursor = true,
[13855]303        ShowConfigButton = false,
[13850]304        YAxisTicks = 5,
305      };
[14852]306      plot.VariableValueChanged += async (o, e) => {
307        var recalculations = VisiblePartialDependencePlots
308          .Except(new[] { (IPartialDependencePlot)o })
[14826]309          .Select(async chart => {
310            await chart.RecalculateAsync(updateOnFinish: false, resetYAxis: false);
311          }).ToList();
[13850]312        await Task.WhenAll(recalculations);
[13843]313
[13850]314        if (recalculations.All(t => t.IsCompleted))
315          SetupYAxis();
316      };
[14852]317      plot.Configure(new[] { Content }, sharedFixedVariables, variableName, Points);
318      plot.SolutionAdded += partialDependencePlot_SolutionAdded;
319      plot.SolutionRemoved += partialDependencePlot_SolutionRemoved;
320      return plot;
[13850]321    }
[14852]322    private FactorPartialDependencePlot CreateFactorPartialDependencePlot(string variableName, ModifiableDataset sharedFixedVariables) {
323      var plot = new FactorPartialDependencePlot {
[14826]324        Dock = DockStyle.Fill,
325        Margin = Padding.Empty,
326        ShowLegend = false,
327        ShowCursor = true,
328        YAxisTicks = 5,
329      };
[14852]330      plot.VariableValueChanged += async (o, e) => {
331        var recalculations = VisiblePartialDependencePlots
332          .Except(new[] { (FactorPartialDependencePlot)o })
[14826]333          .Select(async chart => {
334            await chart.RecalculateAsync(updateOnFinish: false, resetYAxis: false);
335          }).ToList();
336        await Task.WhenAll(recalculations);
[13850]337
[14826]338        if (recalculations.All(t => t.IsCompleted))
339          SetupYAxis();
340      };
341      var variableValues = Content.ProblemData.Dataset.GetStringValues(variableName).Distinct().OrderBy(n => n).ToList();
[14852]342      plot.Configure(new[] { Content }, sharedFixedVariables, variableName, variableValues);
343      plot.SolutionAdded += partialDependencePlot_SolutionAdded;
344      plot.SolutionRemoved += partialDependencePlot_SolutionRemoved;
345      return plot;
[14826]346    }
[13846]347    private void SetupYAxis() {
348      double axisMin, axisMax;
349      if (automaticYAxisCheckBox.Checked) {
350        double min = double.MaxValue, max = double.MinValue;
[14852]351        foreach (var chart in VisiblePartialDependencePlots) {
[13846]352          if (chart.YMin < min) min = chart.YMin;
353          if (chart.YMax > max) max = chart.YMax;
354        }
355
356        double axisInterval;
357        ChartUtil.CalculateAxisInterval(min, max, 5, out axisMin, out axisMax, out axisInterval);
358      } else {
359        axisMin = limitView.Content.Lower;
360        axisMax = limitView.Content.Upper;
[13843]361      }
362
[14852]363      foreach (var chart in VisiblePartialDependencePlots) {
[13843]364        chart.FixedYAxisMin = axisMin;
365        chart.FixedYAxisMax = axisMax;
366      }
367    }
368
[13850]369    // reorder chart controls so that they always appear in the same order as in the list view
370    // the table layout containing the controls should be suspended before calling this method
371    private void ReOrderControls() {
[14852]372      var tl = partialDependencePlotTableLayout;
[13828]373      tl.Controls.Clear();
[13850]374      int row = 0, column = 0;
[14267]375      double yValue = Content.Model.GetEstimatedValues(sharedFixedVariables, new[] { 0 }).Single();
376      string title = Content.ProblemData.TargetVariable + ": " + yValue.ToString("G5", CultureInfo.CurrentCulture);
377
[14014]378      foreach (var v in VisibleVariables) {
379        var chartsPanel = groupingPanels[v];
[13850]380        tl.Controls.Add(chartsPanel, column, row);
[14014]381
[14852]382        var chart = partialDependencePlots[v];
[14267]383        chart.YAxisTitle = column == 0 ? title : string.Empty;
[13850]384        column++;
[14014]385
[13850]386        if (column == MaxColumns) {
387          row++;
388          column = 0;
389        }
390      }
[13828]391    }
[13808]392
[13995]393    private void SetStyles() {
[14852]394      var tl = partialDependencePlotTableLayout;
[13995]395      tl.RowStyles.Clear();
396      tl.ColumnStyles.Clear();
397      int numVariables = VisibleVariables.Count();
398      if (numVariables == 0)
399        return;
400
401      // set column styles
402      tl.ColumnCount = Math.Min(numVariables, MaxColumns);
403      for (int c = 0; c < tl.ColumnCount; c++)
404        tl.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100.0f / tl.ColumnCount));
405
406      // set row styles
407      tl.RowCount = (int)Math.Ceiling((double)numVariables / tl.ColumnCount);
408      var columnWidth = tl.Width / tl.ColumnCount; // assume all columns have the same width
409      var rowHeight = (int)(0.8 * columnWidth);
410      for (int r = 0; r < tl.RowCount; r++)
411        tl.RowStyles.Add(new RowStyle(SizeType.Absolute, rowHeight));
412    }
413
[14852]414    private async void partialDependencePlot_SolutionAdded(object sender, EventArgs<IRegressionSolution> e) {
[13995]415      var solution = e.Value;
[14852]416      foreach (var chart in partialDependencePlots.Values) {
[13995]417        if (sender == chart) continue;
418        await chart.AddSolutionAsync(solution);
419      }
420    }
421
[14852]422    private async void partialDependencePlot_SolutionRemoved(object sender, EventArgs<IRegressionSolution> e) {
[13995]423      var solution = e.Value;
[14852]424      foreach (var chart in partialDependencePlots.Values) {
[13995]425        if (sender == chart) continue;
426        await chart.RemoveSolutionAsync(solution);
427      }
428    }
429
[13842]430    private async void variableListView_ItemChecked(object sender, ItemCheckedEventArgs e) {
[13808]431      var item = e.Item;
432      var variable = item.Text;
[14852]433      var plot = partialDependencePlots[variable];
[13850]434      var chartsPanel = groupingPanels[variable];
[14852]435      var tl = partialDependencePlotTableLayout;
[13850]436
[13817]437      tl.SuspendLayout();
[13808]438      if (item.Checked) {
[13850]439        tl.Controls.Add(chartsPanel);
[14852]440        await plot.RecalculateAsync(false, false);
[13808]441      } else {
[13850]442        tl.Controls.Remove(chartsPanel);
[13808]443      }
[13843]444
[13850]445      if (tl.Controls.Count > 0) {
446        SetupYAxis();
447        ReOrderControls();
[13995]448        SetStyles();
[13828]449      }
[13817]450      tl.ResumeLayout();
[14021]451      tl.Refresh();
452      densityComboBox_SelectedIndexChanged(this, EventArgs.Empty);
[13808]453    }
[13846]454
455    private void automaticYAxisCheckBox_CheckedChanged(object sender, EventArgs e) {
456      limitView.ReadOnly = automaticYAxisCheckBox.Checked;
457      SetupYAxis();
[14852]458      partialDependencePlotTableLayout.Refresh();
[14021]459      densityComboBox_SelectedIndexChanged(this, EventArgs.Empty); // necessary to realign the density plots
[13846]460    }
461
462    private void limit_ValueChanged(object sender, EventArgs e) {
463      if (automaticYAxisCheckBox.Checked)
464        return;
465      SetupYAxis();
[14852]466      partialDependencePlotTableLayout.Refresh();
[14021]467      densityComboBox_SelectedIndexChanged(this, EventArgs.Empty); // necessary to realign the density plots
[13846]468    }
[13850]469
470    private void densityComboBox_SelectedIndexChanged(object sender, EventArgs e) {
[14021]471      if (Content == null)
472        return;
473
[13850]474      int si = densityComboBox.SelectedIndex;
475      if (si == 0) {
476        foreach (var densityChart in densityCharts.Values)
477          densityChart.Visible = false;
478      } else {
479        var indices = GetDensityIndices(si).ToList();
480
481        foreach (var entry in densityCharts) {
482          var variableName = entry.Key;
483          var densityChart = entry.Value;
[14852]484          if (!VisibleVariables.Contains(variableName) || partialDependencePlots[variableName].IsZoomed)
[13850]485            continue;
[14089]486
[13850]487          UpdateDensityChart(densityChart, variableName, indices);
488        }
489      }
490    }
491    private IEnumerable<int> GetDensityIndices(int selectedIndex) {
492      var problemData = Content.ProblemData;
493      return
494        selectedIndex == 1 ? problemData.TrainingIndices :
495        selectedIndex == 2 ? problemData.TestIndices :
496        problemData.AllIndices;
497    }
498    private void UpdateDensityChart(DensityChart densityChart, string variable, IList<int> indices = null) {
499      if (densityComboBox.SelectedIndex == 0)
500        return;
501      if (indices == null) {
502        indices = GetDensityIndices(densityComboBox.SelectedIndex).ToList();
503      }
[14826]504      if (Content.ProblemData.Dataset.VariableHasType<double>(variable)) {
505        var data = Content.ProblemData.Dataset.GetDoubleValues(variable, indices).ToList();
[14852]506        var plot = partialDependencePlots[variable] as PartialDependencePlot;
507        if (plot != null) {
508          var min = plot.FixedXAxisMin;
509          var max = plot.FixedXAxisMax;
510          var buckets = plot.DrawingSteps;
[14826]511          if (min.HasValue && max.HasValue) {
512            densityChart.UpdateChart(data, min.Value, max.Value, buckets);
[14852]513            densityChart.Width = plot.Width;
[13850]514
[14852]515            var gcPlotPosition = plot.InnerPlotPosition;
516            densityChart.Left = (int)(gcPlotPosition.X / 100.0 * plot.Width);
517            densityChart.Width = (int)(gcPlotPosition.Width / 100.0 * plot.Width);
[13850]518
[14826]519            densityChart.Visible = true;
520          }
[14852]521          plot.UpdateTitlePosition();
[14826]522        }
523      } else if (Content.ProblemData.Dataset.VariableHasType<string>(variable)) {
524        var data = Content.ProblemData.Dataset.GetStringValues(variable).ToList();
[14852]525        var plot = partialDependencePlots[variable] as FactorPartialDependencePlot;
526        if (plot != null) {
[14826]527          densityChart.UpdateChart(data);
[14852]528          densityChart.Width = plot.Width;
[14826]529
[14852]530          var gcPlotPosition = plot.InnerPlotPosition;
531          densityChart.Left = (int)(gcPlotPosition.X / 100.0 * plot.Width);
532          densityChart.Width = (int)(gcPlotPosition.Width / 100.0 * plot.Width);
[14826]533
534          densityChart.Visible = true;
535
[14852]536          plot.UpdateTitlePosition();
[14826]537        }
[13850]538      }
539    }
[13995]540
[14089]541    private void columnsNumericUpDown_ValueChanged(object sender, EventArgs e) {
542      MaxColumns = (int)columnsNumericUpDown.Value;
[13995]543      int columns = Math.Min(VisibleVariables.Count(), MaxColumns);
544      if (columns > 0) {
[14852]545        var tl = partialDependencePlotTableLayout;
[13995]546        MaxColumns = columns;
547        tl.SuspendLayout();
548        ReOrderControls();
549        SetStyles();
[14021]550        tl.ResumeLayout();
551        tl.Refresh();
552        densityComboBox_SelectedIndexChanged(this, EventArgs.Empty);
[13995]553      }
554    }
555
[14021]556    private async void solution_ModelChanged(object sender, EventArgs e) {
557      foreach (var variable in VisibleVariables) {
[14852]558        var pdp = partialDependencePlots[variable];
[14021]559        var densityChart = densityCharts[variable];
560        // recalculate and refresh
[14852]561        await pdp.RecalculateAsync(false, false);
562        pdp.Refresh();
[14021]563        UpdateDensityChart(densityChart, variable);
[13996]564      }
[13995]565    }
[13808]566  }
567}
Note: See TracBrowser for help on using the repository browser.