Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/FactorGradientChart.Designer.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/FactorGradientChart.Designer.cs	(revision 15131)
+++ 	(revision )
@@ -1,159 +1,0 @@
-﻿namespace HeuristicLab.Problems.DataAnalysis.Views {
-  partial class FactorGradientChart {
-    /// <summary> 
-    /// Required designer variable.
-    /// </summary>
-    private System.ComponentModel.IContainer components = null;
-
-    /// <summary> 
-    /// Clean up any resources being used.
-    /// </summary>
-    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
-    protected override void Dispose(bool disposing) {
-      if (disposing && (components != null)) {
-        components.Dispose();
-      }
-      base.Dispose(disposing);
-    }
-
-    #region Component Designer generated code
-
-    /// <summary> 
-    /// Required method for Designer support - do not modify 
-    /// the contents of this method with the code editor.
-    /// </summary>
-    private void InitializeComponent() {
-      this.components = new System.ComponentModel.Container();
-      System.Windows.Forms.DataVisualization.Charting.VerticalLineAnnotation verticalLineAnnotation1 = new System.Windows.Forms.DataVisualization.Charting.VerticalLineAnnotation();
-      System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
-      System.Windows.Forms.DataVisualization.Charting.StripLine stripLine1 = new System.Windows.Forms.DataVisualization.Charting.StripLine();
-      System.Windows.Forms.DataVisualization.Charting.StripLine stripLine2 = new System.Windows.Forms.DataVisualization.Charting.StripLine();
-      System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
-      System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series();
-      System.Windows.Forms.DataVisualization.Charting.Series series2 = new System.Windows.Forms.DataVisualization.Charting.Series();
-      System.Windows.Forms.DataVisualization.Charting.Series series3 = new System.Windows.Forms.DataVisualization.Charting.Series();
-      System.Windows.Forms.DataVisualization.Charting.Series series4 = new System.Windows.Forms.DataVisualization.Charting.Series();
-      System.Windows.Forms.DataVisualization.Charting.Title title1 = new System.Windows.Forms.DataVisualization.Charting.Title();
-      this.calculationPendingLabel = new System.Windows.Forms.Label();
-      this.calculationPendingTimer = new System.Windows.Forms.Timer(this.components);
-      this.chart = new HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart();
-      this.toolTip = new System.Windows.Forms.ToolTip(this.components);
-      ((System.ComponentModel.ISupportInitialize)(this.chart)).BeginInit();
-      this.SuspendLayout();
-      // 
-      // calculationPendingLabel
-      // 
-      this.calculationPendingLabel.BackColor = System.Drawing.Color.White;
-      this.calculationPendingLabel.Image = HeuristicLab.Common.Resources.VSImageLibrary.Timer;
-      this.calculationPendingLabel.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
-      this.calculationPendingLabel.Location = new System.Drawing.Point(3, 3);
-      this.calculationPendingLabel.Margin = new System.Windows.Forms.Padding(0);
-      this.calculationPendingLabel.Name = "calculationPendingLabel";
-      this.calculationPendingLabel.Size = new System.Drawing.Size(17, 17);
-      this.calculationPendingLabel.TabIndex = 1;
-      this.calculationPendingLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
-      this.calculationPendingLabel.Visible = false;
-      // 
-      // calculationPendingTimer
-      // 
-      this.calculationPendingTimer.Tick += new System.EventHandler(this.calculationPendingTimer_Tick);
-      // 
-      // chart
-      // 
-      this.chart.AllowDrop = true;
-      verticalLineAnnotation1.AllowMoving = true;
-      verticalLineAnnotation1.AxisXName = "ChartArea\\rX";
-      verticalLineAnnotation1.ClipToChartArea = "ChartArea";
-      verticalLineAnnotation1.IsInfinitive = true;
-      verticalLineAnnotation1.LineColor = System.Drawing.Color.Red;
-      verticalLineAnnotation1.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
-      verticalLineAnnotation1.Name = "VerticalLineAnnotation";
-      verticalLineAnnotation1.YAxisName = "ChartArea\\rY";
-      this.chart.Annotations.Add(verticalLineAnnotation1);
-      chartArea1.AxisX.IsMarginVisible = false;
-      stripLine1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(223)))), ((int)(((byte)(58)))), ((int)(((byte)(2)))));
-      stripLine2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(223)))), ((int)(((byte)(58)))), ((int)(((byte)(2)))));
-      chartArea1.AxisX.StripLines.Add(stripLine1);
-      chartArea1.AxisX.StripLines.Add(stripLine2);
-      chartArea1.Name = "ChartArea";
-      chartArea1.Position.Auto = false;
-      chartArea1.Position.Height = 90F;
-      chartArea1.Position.Width = 100F;
-      chartArea1.Position.Y = 10F;
-      this.chart.ChartAreas.Add(chartArea1);
-      this.chart.Dock = System.Windows.Forms.DockStyle.Fill;
-      legend1.Alignment = System.Drawing.StringAlignment.Center;
-      legend1.Docking = System.Windows.Forms.DataVisualization.Charting.Docking.Top;
-      legend1.LegendItemOrder = System.Windows.Forms.DataVisualization.Charting.LegendItemOrder.ReversedSeriesOrder;
-      legend1.LegendStyle = System.Windows.Forms.DataVisualization.Charting.LegendStyle.Row;
-      legend1.Name = "Default";
-      this.chart.Legends.Add(legend1);
-      this.chart.Location = new System.Drawing.Point(0, 0);
-      this.chart.Name = "chart";
-      series1.BorderColor = System.Drawing.Color.Red;
-      series1.BorderDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
-      series1.ChartArea = "ChartArea";
-      series1.IsVisibleInLegend = false;
-      series1.Legend = "Default";
-      series1.Name = "Series1";
-      series1.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String;
-      series1.YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;
-      series2.ChartArea = "ChartArea";
-      series2.IsVisibleInLegend = false;
-      series2.Legend = "Default";
-      series2.Name = "Series2";
-      series2.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String;
-      series3.ChartArea = "ChartArea";
-      series3.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.BoxPlot;
-      series3.Color = System.Drawing.Color.Black;
-      series3.Legend = "Default";
-      series3.Name = "Series3";
-      series3.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String;
-      series3.YValuesPerPoint = 6;
-      series4.ChartArea = "ChartArea";
-      series4.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.BoxPlot;
-      series4.Legend = "Default";
-      series4.Name = "Series4";
-      series4.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String;
-      series4.YValuesPerPoint = 6;
-      this.chart.Series.Add(series1);
-      this.chart.Series.Add(series2);
-      this.chart.Series.Add(series3);
-      this.chart.Series.Add(series4);
-      this.chart.Size = new System.Drawing.Size(453, 308);
-      this.chart.TabIndex = 0;
-      title1.Alignment = System.Drawing.ContentAlignment.TopCenter;
-      title1.DockedToChartArea = "ChartArea";
-      title1.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
-      title1.IsDockedInsideChartArea = false;
-      title1.Name = "Title";
-      title1.Text = "[Title]";
-      this.chart.Titles.Add(title1);
-      this.chart.SelectionRangeChanged += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.CursorEventArgs>(this.chart_SelectionRangeChanged);
-      this.chart.PostPaint += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.ChartPaintEventArgs>(this.chart_PostPaint);
-      this.chart.DragDrop += new System.Windows.Forms.DragEventHandler(this.chart_DragDrop);
-      this.chart.DragEnter += new System.Windows.Forms.DragEventHandler(this.chart_DragEnter);
-      this.chart.MouseClick += new System.Windows.Forms.MouseEventHandler(this.chart_MouseClick);
-      this.chart.Resize += new System.EventHandler(this.chart_Resize);
-      // 
-      // FactorGradientChart
-      // 
-      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-      this.Controls.Add(this.calculationPendingLabel);
-      this.Controls.Add(this.chart);
-      this.Name = "FactorGradientChart";
-      this.Size = new System.Drawing.Size(453, 308);
-      ((System.ComponentModel.ISupportInitialize)(this.chart)).EndInit();
-      this.ResumeLayout(false);
-
-    }
-
-    #endregion
-
-    private HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart chart;
-    private System.Windows.Forms.Label calculationPendingLabel;
-    private System.Windows.Forms.Timer calculationPendingTimer;
-    private System.Windows.Forms.ToolTip toolTip;
-  }
-}
Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/FactorGradientChart.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/FactorGradientChart.cs	(revision 15131)
+++ 	(revision )
@@ -1,565 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-using System.Windows.Forms.DataVisualization.Charting;
-using HeuristicLab.Common;
-using HeuristicLab.MainForm.WindowsForms;
-using HeuristicLab.Visualization.ChartControlsExtensions;
-
-namespace HeuristicLab.Problems.DataAnalysis.Views {
-  public partial class FactorGradientChart : UserControl, IGradientChart {
-    private ModifiableDataset sharedFixedVariables; // used for syncronising variable values between charts
-    private ModifiableDataset internalDataset; // holds the x values for each point drawn
-
-    private CancellationTokenSource cancelCurrentRecalculateSource;
-
-    private readonly List<IRegressionSolution> solutions;
-    private readonly Dictionary<IRegressionSolution, Series> seriesCache;
-    private readonly Dictionary<IRegressionSolution, Series> ciSeriesCache;
-
-    #region Properties
-    public string XAxisTitle {
-      get { return chart.ChartAreas[0].AxisX.Title; }
-      set { chart.ChartAreas[0].AxisX.Title = value; }
-    }
-
-    public string YAxisTitle {
-      get { return chart.ChartAreas[0].AxisY.Title; }
-      set { chart.ChartAreas[0].AxisY.Title = value; }
-    }
-
-    public bool ShowLegend {
-      get { return chart.Legends[0].Enabled; }
-      set { chart.Legends[0].Enabled = value; }
-    }
-    public bool ShowCursor {
-      get { return chart.Annotations[0].Visible; }
-      set {
-        chart.Annotations[0].Visible = value;
-        if (!value) chart.Titles[0].Text = string.Empty;
-      }
-    }
-
-    private int yAxisTicks = 5;
-    public int YAxisTicks {
-      get { return yAxisTicks; }
-      set {
-        if (value != yAxisTicks) {
-          yAxisTicks = value;
-          SetupAxis(chart.ChartAreas[0].AxisY, yMin, yMax, YAxisTicks, FixedYAxisMin, FixedYAxisMax);
-          RecalculateInternalDataset();
-        }
-      }
-    }
-    private double? fixedYAxisMin;
-    public double? FixedYAxisMin {
-      get { return fixedYAxisMin; }
-      set {
-        if ((value.HasValue && fixedYAxisMin.HasValue && !value.Value.IsAlmost(fixedYAxisMin.Value)) || (value.HasValue != fixedYAxisMin.HasValue)) {
-          fixedYAxisMin = value;
-          SetupAxis(chart.ChartAreas[0].AxisY, yMin, yMax, YAxisTicks, FixedYAxisMin, FixedYAxisMax);
-        }
-      }
-    }
-    private double? fixedYAxisMax;
-    public double? FixedYAxisMax {
-      get { return fixedYAxisMax; }
-      set {
-        if ((value.HasValue && fixedYAxisMax.HasValue && !value.Value.IsAlmost(fixedYAxisMax.Value)) || (value.HasValue != fixedYAxisMax.HasValue)) {
-          fixedYAxisMax = value;
-          SetupAxis(chart.ChartAreas[0].AxisY, yMin, yMax, YAxisTicks, FixedYAxisMin, FixedYAxisMax);
-        }
-      }
-    }
-
-    private string freeVariable;
-    public string FreeVariable {
-      get { return freeVariable; }
-      set {
-        if (value == freeVariable) return;
-        if (solutions.Any(s => !s.ProblemData.Dataset.StringVariables.Contains(value))) {
-          throw new ArgumentException("Variable does not exist in the ProblemData of the Solutions.");
-        }
-        freeVariable = value;
-        RecalculateInternalDataset();
-      }
-    }
-
-    private double yMin;
-    public double YMin {
-      get { return yMin; }
-    }
-    private double yMax;
-    public double YMax {
-      get { return yMax; }
-    }
-
-    public bool IsZoomed {
-      get { return chart.ChartAreas[0].AxisX.ScaleView.IsZoomed; }
-    }
-
-    internal ElementPosition InnerPlotPosition {
-      get { return chart.ChartAreas[0].InnerPlotPosition; }
-    }
-    #endregion
-
-    private List<string> variableValues;
-
-    public event EventHandler ChartPostPaint;
-
-    public FactorGradientChart() {
-      InitializeComponent();
-
-      solutions = new List<IRegressionSolution>();
-      seriesCache = new Dictionary<IRegressionSolution, Series>();
-      ciSeriesCache = new Dictionary<IRegressionSolution, Series>();
-
-      // Configure axis
-      chart.CustomizeAllChartAreas();
-      chart.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
-      chart.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
-      chart.ChartAreas[0].CursorX.Interval = 0;
-
-      chart.ChartAreas[0].CursorY.IsUserSelectionEnabled = true;
-      chart.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
-      chart.ChartAreas[0].CursorY.Interval = 0;
-
-      Disposed += GradientChart_Disposed;
-    }
-
-    private void GradientChart_Disposed(object sender, EventArgs e) {
-      if (cancelCurrentRecalculateSource != null)
-        cancelCurrentRecalculateSource.Cancel();
-    }
-
-    public void Configure(IEnumerable<IRegressionSolution> solutions, ModifiableDataset sharedFixedVariables, string freeVariable, IList<string> variableValues, bool initializeAxisRanges = true) {
-      if (!SolutionsCompatible(solutions))
-        throw new ArgumentException("Solutions are not compatible with the problem data.");
-      this.freeVariable = freeVariable;
-      this.variableValues = new List<string>(variableValues);
-
-      this.solutions.Clear();
-      this.solutions.AddRange(solutions);
-
-      // add an event such that whenever a value is changed in the shared dataset, 
-      // this change is reflected in the internal dataset (where the value becomes a whole column)
-      if (this.sharedFixedVariables != null)
-        this.sharedFixedVariables.ItemChanged -= sharedFixedVariables_ItemChanged;
-      this.sharedFixedVariables = sharedFixedVariables;
-      this.sharedFixedVariables.ItemChanged += sharedFixedVariables_ItemChanged;
-
-      RecalculateInternalDataset();
-
-      chart.Series.Clear();
-      seriesCache.Clear();
-      ciSeriesCache.Clear();
-      foreach (var solution in this.solutions) {
-        var series = CreateSeries(solution);
-        seriesCache.Add(solution, series.Item1);
-        if (series.Item2 != null)
-          ciSeriesCache.Add(solution, series.Item2);
-      }
-
-      InitSeriesData();
-      OrderAndColorSeries();
-
-    }
-
-    public async Task RecalculateAsync(bool updateOnFinish = true, bool resetYAxis = true) {
-      if (IsDisposed
-        || sharedFixedVariables == null || !solutions.Any() || string.IsNullOrEmpty(freeVariable)
-        || !variableValues.Any())
-        return;
-
-      calculationPendingTimer.Start();
-
-      // cancel previous recalculate call
-      if (cancelCurrentRecalculateSource != null)
-        cancelCurrentRecalculateSource.Cancel();
-      cancelCurrentRecalculateSource = new CancellationTokenSource();
-      var cancellationToken = cancelCurrentRecalculateSource.Token;
-
-      // Update series
-      try {
-        var limits = await UpdateAllSeriesDataAsync(cancellationToken);
-
-        yMin = limits.Lower;
-        yMax = limits.Upper;
-        // Set y-axis
-        if (resetYAxis)
-          SetupAxis(chart.ChartAreas[0].AxisY, yMin, yMax, YAxisTicks, FixedYAxisMin, FixedYAxisMax);
-
-        calculationPendingTimer.Stop();
-        calculationPendingLabel.Visible = false;
-        if (updateOnFinish)
-          Update();
-      } catch (OperationCanceledException) { } catch (AggregateException ae) {
-        if (!ae.InnerExceptions.Any(e => e is OperationCanceledException))
-          throw;
-      }
-    }
-
-    public void UpdateTitlePosition() {
-      var title = chart.Titles[0];
-      var plotArea = InnerPlotPosition;
-
-      title.Visible = plotArea.Width != 0;
-
-      title.Position.X = plotArea.X + (plotArea.Width / 2);
-    }
-
-    private void SetupAxis(Axis axis, double minValue, double maxValue, int ticks, double? fixedAxisMin, double? fixedAxisMax) {
-      if (minValue < maxValue) {
-        double axisMin, axisMax, axisInterval;
-        ChartUtil.CalculateAxisInterval(minValue, maxValue, ticks, out axisMin, out axisMax, out axisInterval);
-        axis.Minimum = fixedAxisMin ?? axisMin;
-        axis.Maximum = fixedAxisMax ?? axisMax;
-        axis.Interval = (axis.Maximum - axis.Minimum) / ticks;
-      }
-
-      try {
-        chart.ChartAreas[0].RecalculateAxesScale();
-      } catch (InvalidOperationException) {
-        // Can occur if eg. axis min == axis max
-      }
-    }
-
-
-    private void RecalculateInternalDataset() {
-      if (sharedFixedVariables == null)
-        return;
-
-      var factorValues = new List<string>(variableValues);
-
-      var variables = sharedFixedVariables.VariableNames.ToList();
-      var values = new List<IList>();
-      foreach (var varName in variables) {
-        if (varName == FreeVariable) {
-          values.Add(factorValues);
-        } else if (sharedFixedVariables.VariableHasType<double>(varName)) {
-          values.Add(Enumerable.Repeat(sharedFixedVariables.GetDoubleValue(varName, 0), factorValues.Count).ToList());
-        } else if (sharedFixedVariables.VariableHasType<string>(varName)) {
-          values.Add(Enumerable.Repeat(sharedFixedVariables.GetStringValue(varName, 0), factorValues.Count).ToList());
-        }
-      }
-
-      internalDataset = new ModifiableDataset(variables, values);
-    }
-
-    private Tuple<Series, Series> CreateSeries(IRegressionSolution solution) {
-      var series = new Series {
-        ChartType = SeriesChartType.Column,
-        Name = solution.ProblemData.TargetVariable + " " + solutions.IndexOf(solution),
-        XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String
-      };
-      series.LegendText = series.Name;
-
-      Series confidenceIntervalSeries = null;
-      confidenceIntervalSeries = new Series {
-        ChartType = SeriesChartType.BoxPlot,
-        XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String,
-        Color = Color.Black,
-        YValuesPerPoint = 5,
-        Name = "95% Conf. Interval " + series.Name,
-        IsVisibleInLegend = false
-      };
-      return Tuple.Create(series, confidenceIntervalSeries);
-    }
-
-    private void OrderAndColorSeries() {
-      chart.SuspendRepaint();
-
-      chart.Series.Clear();
-      // Add mean series for applying palette colors
-      foreach (var solution in solutions) {
-        chart.Series.Add(seriesCache[solution]);
-      }
-
-      chart.Palette = ChartColorPalette.BrightPastel;
-      chart.ApplyPaletteColors();
-      chart.Palette = ChartColorPalette.None;
-
-      // Add confidence interval series after its coresponding series for correct z index
-      foreach (var solution in solutions) {
-        Series ciSeries;
-        if (ciSeriesCache.TryGetValue(solution, out ciSeries)) {
-          int idx = chart.Series.IndexOf(seriesCache[solution]);
-          chart.Series.Insert(idx + 1, ciSeries);
-        }
-      }
-
-      chart.ResumeRepaint(true);
-    }
-
-    private async Task<DoubleLimit> UpdateAllSeriesDataAsync(CancellationToken cancellationToken) {
-      var updateTasks = solutions.Select(solution => UpdateSeriesDataAsync(solution, cancellationToken));
-
-      double min = double.MaxValue, max = double.MinValue;
-      foreach (var update in updateTasks) {
-        var limit = await update;
-        if (limit.Lower < min) min = limit.Lower;
-        if (limit.Upper > max) max = limit.Upper;
-      }
-
-      return new DoubleLimit(min, max);
-    }
-
-    private Task<DoubleLimit> UpdateSeriesDataAsync(IRegressionSolution solution, CancellationToken cancellationToken) {
-      return Task.Run(() => {
-        var yvalues = solution.Model.GetEstimatedValues(internalDataset, Enumerable.Range(0, internalDataset.Rows)).ToList();
-
-        double min = double.MaxValue, max = double.MinValue;
-
-        var series = seriesCache[solution];
-        for (int i = 0; i < variableValues.Count; i++) {
-          series.Points[i].SetValueXY(variableValues[i], yvalues[i]);
-          if (yvalues[i] < min) min = yvalues[i];
-          if (yvalues[i] > max) max = yvalues[i];
-        }
-        chart.Invalidate();
-
-        cancellationToken.ThrowIfCancellationRequested();
-
-        var confidenceBoundSolution = solution as IConfidenceRegressionSolution;
-        if (confidenceBoundSolution != null) {
-          var confidenceIntervalSeries = ciSeriesCache[solution];
-          var variances = confidenceBoundSolution.Model.GetEstimatedVariances(internalDataset, Enumerable.Range(0, internalDataset.Rows)).ToList();
-          for (int i = 0; i < variableValues.Count; i++) {
-            var lower = yvalues[i] - 1.96 * Math.Sqrt(variances[i]);
-            var upper = yvalues[i] + 1.96 * Math.Sqrt(variances[i]);
-            confidenceIntervalSeries.Points[i].SetValueXY(variableValues[i], lower, upper, yvalues[i], yvalues[i], yvalues[i]);
-            if (lower < min) min = lower;
-            if (upper > max) max = upper;
-          }
-          chart.Invalidate();
-        }
-
-        cancellationToken.ThrowIfCancellationRequested();
-        return new DoubleLimit(min, max);
-      }, cancellationToken);
-    }
-
-    private void InitSeriesData() {
-      if (internalDataset == null)
-        return;
-
-      foreach (var solution in solutions)
-        InitSeriesData(solution, variableValues);
-    }
-
-    private void InitSeriesData(IRegressionSolution solution, IList<string> values) {
-
-      var series = seriesCache[solution];
-      series.Points.SuspendUpdates();
-      series.Points.Clear();
-      for (int i = 0; i < values.Count; i++) {
-        series.Points.AddXY(values[i], 0.0);
-        series.Points.Last().ToolTip = values[i];
-      }
-
-      UpdateAllSeriesStyles(variableValues.IndexOf(sharedFixedVariables.GetStringValue(FreeVariable, 0)));
-      series.Points.ResumeUpdates();
-
-      Series confidenceIntervalSeries;
-      if (ciSeriesCache.TryGetValue(solution, out confidenceIntervalSeries)) {
-        confidenceIntervalSeries.Points.SuspendUpdates();
-        confidenceIntervalSeries.Points.Clear();
-        for (int i = 0; i < values.Count; i++)
-          confidenceIntervalSeries.Points.AddXY(values[i], 0.0, 0.0, 0.0, 0.0, 0.0);
-        confidenceIntervalSeries.Points.ResumeUpdates();
-      }
-    }
-
-    public async Task AddSolutionAsync(IRegressionSolution solution) {
-      if (!SolutionsCompatible(solutions.Concat(new[] { solution })))
-        throw new ArgumentException("The solution is not compatible with the problem data.");
-      if (solutions.Contains(solution))
-        return;
-
-      solutions.Add(solution);
-
-      var series = CreateSeries(solution);
-      seriesCache.Add(solution, series.Item1);
-      if (series.Item2 != null)
-        ciSeriesCache.Add(solution, series.Item2);
-
-      InitSeriesData(solution, variableValues);
-      OrderAndColorSeries();
-
-      await RecalculateAsync();
-      var args = new EventArgs<IRegressionSolution>(solution);
-      OnSolutionAdded(this, args);
-    }
-
-    public async Task RemoveSolutionAsync(IRegressionSolution solution) {
-      throw new NotSupportedException();
-    }
-
-    private static bool SolutionsCompatible(IEnumerable<IRegressionSolution> solutions) {
-      var refSolution = solutions.First();
-      var refSolVars = refSolution.ProblemData.Dataset.VariableNames;
-      foreach (var solution in solutions.Skip(1)) {
-        var variables1 = solution.ProblemData.Dataset.VariableNames;
-        if (!variables1.All(refSolVars.Contains))
-          return false;
-
-        foreach (var factorVar in variables1.Where(solution.ProblemData.Dataset.VariableHasType<string>)) {
-          var distinctVals = refSolution.ProblemData.Dataset.GetStringValues(factorVar).Distinct();
-          if (solution.ProblemData.Dataset.GetStringValues(factorVar).Any(val => !distinctVals.Contains(val))) return false;
-        }
-      }
-      return true;
-    }
-
-    #region Events
-    public event EventHandler<EventArgs<IRegressionSolution>> SolutionAdded;
-    public void OnSolutionAdded(object sender, EventArgs<IRegressionSolution> args) {
-      var added = SolutionAdded;
-      if (added == null) return;
-      added(sender, args);
-    }
-
-    public event EventHandler<EventArgs<IRegressionSolution>> SolutionRemoved;
-    public void OnSolutionRemoved(object sender, EventArgs<IRegressionSolution> args) {
-      var removed = SolutionRemoved;
-      if (removed == null) return;
-      removed(sender, args);
-    }
-
-    public event EventHandler VariableValueChanged;
-    public void OnVariableValueChanged(object sender, EventArgs args) {
-      var changed = VariableValueChanged;
-      if (changed == null) return;
-      changed(sender, args);
-    }
-
-    public event EventHandler ZoomChanged;
-    public void OnZoomChanged(object sender, EventArgs args) {
-      var changed = ZoomChanged;
-      if (changed == null) return;
-      changed(sender, args);
-    }
-
-    private void sharedFixedVariables_ItemChanged(object o, EventArgs<int, int> e) {
-      if (o != sharedFixedVariables) return;
-      var variables = sharedFixedVariables.VariableNames.ToList();
-      var rowIndex = e.Value;
-      var columnIndex = e.Value2;
-
-      var variableName = variables[columnIndex];
-      if (variableName == FreeVariable) return;
-      if (internalDataset.VariableHasType<double>(variableName)) {
-        var v = sharedFixedVariables.GetDoubleValue(variableName, rowIndex);
-        var values = new List<double>(Enumerable.Repeat(v, internalDataset.Rows));
-        internalDataset.ReplaceVariable(variableName, values);
-      } else if (internalDataset.VariableHasType<string>(variableName)) {
-        var v = sharedFixedVariables.GetStringValue(variableName, rowIndex);
-        var values = new List<String>(Enumerable.Repeat(v, internalDataset.Rows));
-        internalDataset.ReplaceVariable(variableName, values);
-      } else {
-        // unsupported type 
-        throw new NotSupportedException();
-      }
-    }
-
-    private async void chart_DragDrop(object sender, DragEventArgs e) {
-      var data = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
-      if (data != null) {
-        var solution = data as IRegressionSolution;
-        if (!solutions.Contains(solution))
-          await AddSolutionAsync(solution);
-      }
-    }
-    private void chart_DragEnter(object sender, DragEventArgs e) {
-      if (!e.Data.GetDataPresent(HeuristicLab.Common.Constants.DragDropDataFormat)) return;
-      e.Effect = DragDropEffects.None;
-
-      var data = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
-      var regressionSolution = data as IRegressionSolution;
-      if (regressionSolution != null) {
-        e.Effect = DragDropEffects.Copy;
-      }
-    }
-
-    private void calculationPendingTimer_Tick(object sender, EventArgs e) {
-      calculationPendingLabel.Visible = true;
-      Update();
-    }
-
-    private void chart_SelectionRangeChanged(object sender, CursorEventArgs e) {
-      OnZoomChanged(this, EventArgs.Empty);
-    }
-
-    private void chart_Resize(object sender, EventArgs e) {
-      UpdateTitlePosition();
-    }
-
-    private void chart_PostPaint(object sender, ChartPaintEventArgs e) {
-      if (ChartPostPaint != null)
-        ChartPostPaint(this, EventArgs.Empty);
-    }
-    #endregion
-
-    private void chart_MouseClick(object sender, MouseEventArgs e) {
-      var hitTestResult = chart.HitTest(e.X, e.Y, ChartElementType.DataPoint);
-      if (hitTestResult != null && hitTestResult.ChartElementType == ChartElementType.DataPoint) {
-        var series = hitTestResult.Series;
-        var dataPoint = (DataPoint)hitTestResult.Object;
-        var idx = series.Points.IndexOf(dataPoint);
-        UpdateSelectedValue(variableValues[idx]);
-
-        UpdateAllSeriesStyles(idx);
-      }
-    }
-
-    private void UpdateAllSeriesStyles(int selectedValueIndex) {
-      if (ShowCursor) {
-        chart.Titles[0].Text = FreeVariable + " : " + variableValues[selectedValueIndex];
-        chart.Update();
-      }
-      foreach (var s in seriesCache.Values) {
-        if (s.ChartType == SeriesChartType.Column)
-          for (int i = 0; i < s.Points.Count; i++) {
-            if (i != selectedValueIndex) {
-              s.Points[i].BorderDashStyle = ChartDashStyle.NotSet;
-            } else {
-              s.Points[i].BorderDashStyle = ChartDashStyle.Dash;
-              s.Points[i].BorderColor = Color.Red;
-            }
-          }
-      }
-    }
-
-    private void UpdateSelectedValue(string variableValue) {
-      sharedFixedVariables.SetVariableValue(variableValue, FreeVariable, 0);
-      OnVariableValueChanged(this, EventArgs.Empty);
-    }
-  }
-}
-
Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/FactorPartialDependencePlot.Designer.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/FactorPartialDependencePlot.Designer.cs	(revision 15137)
+++ stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/FactorPartialDependencePlot.Designer.cs	(revision 15137)
@@ -0,0 +1,159 @@
+﻿namespace HeuristicLab.Problems.DataAnalysis.Views {
+  partial class FactorPartialDependencePlot {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      this.components = new System.ComponentModel.Container();
+      System.Windows.Forms.DataVisualization.Charting.VerticalLineAnnotation verticalLineAnnotation1 = new System.Windows.Forms.DataVisualization.Charting.VerticalLineAnnotation();
+      System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
+      System.Windows.Forms.DataVisualization.Charting.StripLine stripLine1 = new System.Windows.Forms.DataVisualization.Charting.StripLine();
+      System.Windows.Forms.DataVisualization.Charting.StripLine stripLine2 = new System.Windows.Forms.DataVisualization.Charting.StripLine();
+      System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
+      System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series();
+      System.Windows.Forms.DataVisualization.Charting.Series series2 = new System.Windows.Forms.DataVisualization.Charting.Series();
+      System.Windows.Forms.DataVisualization.Charting.Series series3 = new System.Windows.Forms.DataVisualization.Charting.Series();
+      System.Windows.Forms.DataVisualization.Charting.Series series4 = new System.Windows.Forms.DataVisualization.Charting.Series();
+      System.Windows.Forms.DataVisualization.Charting.Title title1 = new System.Windows.Forms.DataVisualization.Charting.Title();
+      this.calculationPendingLabel = new System.Windows.Forms.Label();
+      this.calculationPendingTimer = new System.Windows.Forms.Timer(this.components);
+      this.chart = new HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart();
+      this.toolTip = new System.Windows.Forms.ToolTip(this.components);
+      ((System.ComponentModel.ISupportInitialize)(this.chart)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // calculationPendingLabel
+      // 
+      this.calculationPendingLabel.BackColor = System.Drawing.Color.White;
+      this.calculationPendingLabel.Image = HeuristicLab.Common.Resources.VSImageLibrary.Timer;
+      this.calculationPendingLabel.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
+      this.calculationPendingLabel.Location = new System.Drawing.Point(3, 3);
+      this.calculationPendingLabel.Margin = new System.Windows.Forms.Padding(0);
+      this.calculationPendingLabel.Name = "calculationPendingLabel";
+      this.calculationPendingLabel.Size = new System.Drawing.Size(17, 17);
+      this.calculationPendingLabel.TabIndex = 1;
+      this.calculationPendingLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+      this.calculationPendingLabel.Visible = false;
+      // 
+      // calculationPendingTimer
+      // 
+      this.calculationPendingTimer.Tick += new System.EventHandler(this.calculationPendingTimer_Tick);
+      // 
+      // chart
+      // 
+      this.chart.AllowDrop = true;
+      verticalLineAnnotation1.AllowMoving = true;
+      verticalLineAnnotation1.AxisXName = "ChartArea\\rX";
+      verticalLineAnnotation1.ClipToChartArea = "ChartArea";
+      verticalLineAnnotation1.IsInfinitive = true;
+      verticalLineAnnotation1.LineColor = System.Drawing.Color.Red;
+      verticalLineAnnotation1.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
+      verticalLineAnnotation1.Name = "VerticalLineAnnotation";
+      verticalLineAnnotation1.YAxisName = "ChartArea\\rY";
+      this.chart.Annotations.Add(verticalLineAnnotation1);
+      chartArea1.AxisX.IsMarginVisible = false;
+      stripLine1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(223)))), ((int)(((byte)(58)))), ((int)(((byte)(2)))));
+      stripLine2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(223)))), ((int)(((byte)(58)))), ((int)(((byte)(2)))));
+      chartArea1.AxisX.StripLines.Add(stripLine1);
+      chartArea1.AxisX.StripLines.Add(stripLine2);
+      chartArea1.Name = "ChartArea";
+      chartArea1.Position.Auto = false;
+      chartArea1.Position.Height = 90F;
+      chartArea1.Position.Width = 100F;
+      chartArea1.Position.Y = 10F;
+      this.chart.ChartAreas.Add(chartArea1);
+      this.chart.Dock = System.Windows.Forms.DockStyle.Fill;
+      legend1.Alignment = System.Drawing.StringAlignment.Center;
+      legend1.Docking = System.Windows.Forms.DataVisualization.Charting.Docking.Top;
+      legend1.LegendItemOrder = System.Windows.Forms.DataVisualization.Charting.LegendItemOrder.ReversedSeriesOrder;
+      legend1.LegendStyle = System.Windows.Forms.DataVisualization.Charting.LegendStyle.Row;
+      legend1.Name = "Default";
+      this.chart.Legends.Add(legend1);
+      this.chart.Location = new System.Drawing.Point(0, 0);
+      this.chart.Name = "chart";
+      series1.BorderColor = System.Drawing.Color.Red;
+      series1.BorderDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
+      series1.ChartArea = "ChartArea";
+      series1.IsVisibleInLegend = false;
+      series1.Legend = "Default";
+      series1.Name = "Series1";
+      series1.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String;
+      series1.YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;
+      series2.ChartArea = "ChartArea";
+      series2.IsVisibleInLegend = false;
+      series2.Legend = "Default";
+      series2.Name = "Series2";
+      series2.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String;
+      series3.ChartArea = "ChartArea";
+      series3.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.BoxPlot;
+      series3.Color = System.Drawing.Color.Black;
+      series3.Legend = "Default";
+      series3.Name = "Series3";
+      series3.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String;
+      series3.YValuesPerPoint = 6;
+      series4.ChartArea = "ChartArea";
+      series4.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.BoxPlot;
+      series4.Legend = "Default";
+      series4.Name = "Series4";
+      series4.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String;
+      series4.YValuesPerPoint = 6;
+      this.chart.Series.Add(series1);
+      this.chart.Series.Add(series2);
+      this.chart.Series.Add(series3);
+      this.chart.Series.Add(series4);
+      this.chart.Size = new System.Drawing.Size(453, 308);
+      this.chart.TabIndex = 0;
+      title1.Alignment = System.Drawing.ContentAlignment.TopCenter;
+      title1.DockedToChartArea = "ChartArea";
+      title1.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+      title1.IsDockedInsideChartArea = false;
+      title1.Name = "Title";
+      title1.Text = "[Title]";
+      this.chart.Titles.Add(title1);
+      this.chart.SelectionRangeChanged += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.CursorEventArgs>(this.chart_SelectionRangeChanged);
+      this.chart.PostPaint += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.ChartPaintEventArgs>(this.chart_PostPaint);
+      this.chart.DragDrop += new System.Windows.Forms.DragEventHandler(this.chart_DragDrop);
+      this.chart.DragEnter += new System.Windows.Forms.DragEventHandler(this.chart_DragEnter);
+      this.chart.MouseClick += new System.Windows.Forms.MouseEventHandler(this.chart_MouseClick);
+      this.chart.Resize += new System.EventHandler(this.chart_Resize);
+      // 
+      // FactorPartialDependencePlot
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Controls.Add(this.calculationPendingLabel);
+      this.Controls.Add(this.chart);
+      this.Name = "FactorPartialDependencePlot";
+      this.Size = new System.Drawing.Size(453, 308);
+      ((System.ComponentModel.ISupportInitialize)(this.chart)).EndInit();
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    private HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart chart;
+    private System.Windows.Forms.Label calculationPendingLabel;
+    private System.Windows.Forms.Timer calculationPendingTimer;
+    private System.Windows.Forms.ToolTip toolTip;
+  }
+}
Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/FactorPartialDependencePlot.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/FactorPartialDependencePlot.cs	(revision 15137)
+++ stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/FactorPartialDependencePlot.cs	(revision 15137)
@@ -0,0 +1,565 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using System.Windows.Forms.DataVisualization.Charting;
+using HeuristicLab.Common;
+using HeuristicLab.MainForm.WindowsForms;
+using HeuristicLab.Visualization.ChartControlsExtensions;
+
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  public partial class FactorPartialDependencePlot : UserControl, IPartialDependencePlot {
+    private ModifiableDataset sharedFixedVariables; // used for synchronising variable values between charts
+    private ModifiableDataset internalDataset; // holds the x values for each point drawn
+
+    private CancellationTokenSource cancelCurrentRecalculateSource;
+
+    private readonly List<IRegressionSolution> solutions;
+    private readonly Dictionary<IRegressionSolution, Series> seriesCache;
+    private readonly Dictionary<IRegressionSolution, Series> ciSeriesCache;
+
+    #region Properties
+    public string XAxisTitle {
+      get { return chart.ChartAreas[0].AxisX.Title; }
+      set { chart.ChartAreas[0].AxisX.Title = value; }
+    }
+
+    public string YAxisTitle {
+      get { return chart.ChartAreas[0].AxisY.Title; }
+      set { chart.ChartAreas[0].AxisY.Title = value; }
+    }
+
+    public bool ShowLegend {
+      get { return chart.Legends[0].Enabled; }
+      set { chart.Legends[0].Enabled = value; }
+    }
+    public bool ShowCursor {
+      get { return chart.Annotations[0].Visible; }
+      set {
+        chart.Annotations[0].Visible = value;
+        if (!value) chart.Titles[0].Text = string.Empty;
+      }
+    }
+
+    private int yAxisTicks = 5;
+    public int YAxisTicks {
+      get { return yAxisTicks; }
+      set {
+        if (value != yAxisTicks) {
+          yAxisTicks = value;
+          SetupAxis(chart.ChartAreas[0].AxisY, yMin, yMax, YAxisTicks, FixedYAxisMin, FixedYAxisMax);
+          RecalculateInternalDataset();
+        }
+      }
+    }
+    private double? fixedYAxisMin;
+    public double? FixedYAxisMin {
+      get { return fixedYAxisMin; }
+      set {
+        if ((value.HasValue && fixedYAxisMin.HasValue && !value.Value.IsAlmost(fixedYAxisMin.Value)) || (value.HasValue != fixedYAxisMin.HasValue)) {
+          fixedYAxisMin = value;
+          SetupAxis(chart.ChartAreas[0].AxisY, yMin, yMax, YAxisTicks, FixedYAxisMin, FixedYAxisMax);
+        }
+      }
+    }
+    private double? fixedYAxisMax;
+    public double? FixedYAxisMax {
+      get { return fixedYAxisMax; }
+      set {
+        if ((value.HasValue && fixedYAxisMax.HasValue && !value.Value.IsAlmost(fixedYAxisMax.Value)) || (value.HasValue != fixedYAxisMax.HasValue)) {
+          fixedYAxisMax = value;
+          SetupAxis(chart.ChartAreas[0].AxisY, yMin, yMax, YAxisTicks, FixedYAxisMin, FixedYAxisMax);
+        }
+      }
+    }
+
+    private string freeVariable;
+    public string FreeVariable {
+      get { return freeVariable; }
+      set {
+        if (value == freeVariable) return;
+        if (solutions.Any(s => !s.ProblemData.Dataset.StringVariables.Contains(value))) {
+          throw new ArgumentException("Variable does not exist in the ProblemData of the Solutions.");
+        }
+        freeVariable = value;
+        RecalculateInternalDataset();
+      }
+    }
+
+    private double yMin;
+    public double YMin {
+      get { return yMin; }
+    }
+    private double yMax;
+    public double YMax {
+      get { return yMax; }
+    }
+
+    public bool IsZoomed {
+      get { return chart.ChartAreas[0].AxisX.ScaleView.IsZoomed; }
+    }
+
+    internal ElementPosition InnerPlotPosition {
+      get { return chart.ChartAreas[0].InnerPlotPosition; }
+    }
+    #endregion
+
+    private List<string> variableValues;
+
+    public event EventHandler ChartPostPaint;
+
+    public FactorPartialDependencePlot() {
+      InitializeComponent();
+
+      solutions = new List<IRegressionSolution>();
+      seriesCache = new Dictionary<IRegressionSolution, Series>();
+      ciSeriesCache = new Dictionary<IRegressionSolution, Series>();
+
+      // Configure axis
+      chart.CustomizeAllChartAreas();
+      chart.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
+      chart.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
+      chart.ChartAreas[0].CursorX.Interval = 0;
+
+      chart.ChartAreas[0].CursorY.IsUserSelectionEnabled = true;
+      chart.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
+      chart.ChartAreas[0].CursorY.Interval = 0;
+
+      Disposed += Control_Disposed;
+    }
+
+    private void Control_Disposed(object sender, EventArgs e) {
+      if (cancelCurrentRecalculateSource != null)
+        cancelCurrentRecalculateSource.Cancel();
+    }
+
+    public void Configure(IEnumerable<IRegressionSolution> solutions, ModifiableDataset sharedFixedVariables, string freeVariable, IList<string> variableValues, bool initializeAxisRanges = true) {
+      if (!SolutionsCompatible(solutions))
+        throw new ArgumentException("Solutions are not compatible with the problem data.");
+      this.freeVariable = freeVariable;
+      this.variableValues = new List<string>(variableValues);
+
+      this.solutions.Clear();
+      this.solutions.AddRange(solutions);
+
+      // add an event such that whenever a value is changed in the shared dataset, 
+      // this change is reflected in the internal dataset (where the value becomes a whole column)
+      if (this.sharedFixedVariables != null)
+        this.sharedFixedVariables.ItemChanged -= sharedFixedVariables_ItemChanged;
+      this.sharedFixedVariables = sharedFixedVariables;
+      this.sharedFixedVariables.ItemChanged += sharedFixedVariables_ItemChanged;
+
+      RecalculateInternalDataset();
+
+      chart.Series.Clear();
+      seriesCache.Clear();
+      ciSeriesCache.Clear();
+      foreach (var solution in this.solutions) {
+        var series = CreateSeries(solution);
+        seriesCache.Add(solution, series.Item1);
+        if (series.Item2 != null)
+          ciSeriesCache.Add(solution, series.Item2);
+      }
+
+      InitSeriesData();
+      OrderAndColorSeries();
+
+    }
+
+    public async Task RecalculateAsync(bool updateOnFinish = true, bool resetYAxis = true) {
+      if (IsDisposed
+        || sharedFixedVariables == null || !solutions.Any() || string.IsNullOrEmpty(freeVariable)
+        || !variableValues.Any())
+        return;
+
+      calculationPendingTimer.Start();
+
+      // cancel previous recalculate call
+      if (cancelCurrentRecalculateSource != null)
+        cancelCurrentRecalculateSource.Cancel();
+      cancelCurrentRecalculateSource = new CancellationTokenSource();
+      var cancellationToken = cancelCurrentRecalculateSource.Token;
+
+      // Update series
+      try {
+        var limits = await UpdateAllSeriesDataAsync(cancellationToken);
+
+        yMin = limits.Lower;
+        yMax = limits.Upper;
+        // Set y-axis
+        if (resetYAxis)
+          SetupAxis(chart.ChartAreas[0].AxisY, yMin, yMax, YAxisTicks, FixedYAxisMin, FixedYAxisMax);
+
+        calculationPendingTimer.Stop();
+        calculationPendingLabel.Visible = false;
+        if (updateOnFinish)
+          Update();
+      } catch (OperationCanceledException) { } catch (AggregateException ae) {
+        if (!ae.InnerExceptions.Any(e => e is OperationCanceledException))
+          throw;
+      }
+    }
+
+    public void UpdateTitlePosition() {
+      var title = chart.Titles[0];
+      var plotArea = InnerPlotPosition;
+
+      title.Visible = plotArea.Width != 0;
+
+      title.Position.X = plotArea.X + (plotArea.Width / 2);
+    }
+
+    private void SetupAxis(Axis axis, double minValue, double maxValue, int ticks, double? fixedAxisMin, double? fixedAxisMax) {
+      if (minValue < maxValue) {
+        double axisMin, axisMax, axisInterval;
+        ChartUtil.CalculateAxisInterval(minValue, maxValue, ticks, out axisMin, out axisMax, out axisInterval);
+        axis.Minimum = fixedAxisMin ?? axisMin;
+        axis.Maximum = fixedAxisMax ?? axisMax;
+        axis.Interval = (axis.Maximum - axis.Minimum) / ticks;
+      }
+
+      try {
+        chart.ChartAreas[0].RecalculateAxesScale();
+      } catch (InvalidOperationException) {
+        // Can occur if eg. axis min == axis max
+      }
+    }
+
+
+    private void RecalculateInternalDataset() {
+      if (sharedFixedVariables == null)
+        return;
+
+      var factorValues = new List<string>(variableValues);
+
+      var variables = sharedFixedVariables.VariableNames.ToList();
+      var values = new List<IList>();
+      foreach (var varName in variables) {
+        if (varName == FreeVariable) {
+          values.Add(factorValues);
+        } else if (sharedFixedVariables.VariableHasType<double>(varName)) {
+          values.Add(Enumerable.Repeat(sharedFixedVariables.GetDoubleValue(varName, 0), factorValues.Count).ToList());
+        } else if (sharedFixedVariables.VariableHasType<string>(varName)) {
+          values.Add(Enumerable.Repeat(sharedFixedVariables.GetStringValue(varName, 0), factorValues.Count).ToList());
+        }
+      }
+
+      internalDataset = new ModifiableDataset(variables, values);
+    }
+
+    private Tuple<Series, Series> CreateSeries(IRegressionSolution solution) {
+      var series = new Series {
+        ChartType = SeriesChartType.Column,
+        Name = solution.ProblemData.TargetVariable + " " + solutions.IndexOf(solution),
+        XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String
+      };
+      series.LegendText = series.Name;
+
+      Series confidenceIntervalSeries = null;
+      confidenceIntervalSeries = new Series {
+        ChartType = SeriesChartType.BoxPlot,
+        XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.String,
+        Color = Color.Black,
+        YValuesPerPoint = 5,
+        Name = "95% Conf. Interval " + series.Name,
+        IsVisibleInLegend = false
+      };
+      return Tuple.Create(series, confidenceIntervalSeries);
+    }
+
+    private void OrderAndColorSeries() {
+      chart.SuspendRepaint();
+
+      chart.Series.Clear();
+      // Add mean series for applying palette colors
+      foreach (var solution in solutions) {
+        chart.Series.Add(seriesCache[solution]);
+      }
+
+      chart.Palette = ChartColorPalette.BrightPastel;
+      chart.ApplyPaletteColors();
+      chart.Palette = ChartColorPalette.None;
+
+      // Add confidence interval series after its coresponding series for correct z index
+      foreach (var solution in solutions) {
+        Series ciSeries;
+        if (ciSeriesCache.TryGetValue(solution, out ciSeries)) {
+          int idx = chart.Series.IndexOf(seriesCache[solution]);
+          chart.Series.Insert(idx + 1, ciSeries);
+        }
+      }
+
+      chart.ResumeRepaint(true);
+    }
+
+    private async Task<DoubleLimit> UpdateAllSeriesDataAsync(CancellationToken cancellationToken) {
+      var updateTasks = solutions.Select(solution => UpdateSeriesDataAsync(solution, cancellationToken));
+
+      double min = double.MaxValue, max = double.MinValue;
+      foreach (var update in updateTasks) {
+        var limit = await update;
+        if (limit.Lower < min) min = limit.Lower;
+        if (limit.Upper > max) max = limit.Upper;
+      }
+
+      return new DoubleLimit(min, max);
+    }
+
+    private Task<DoubleLimit> UpdateSeriesDataAsync(IRegressionSolution solution, CancellationToken cancellationToken) {
+      return Task.Run(() => {
+        var yvalues = solution.Model.GetEstimatedValues(internalDataset, Enumerable.Range(0, internalDataset.Rows)).ToList();
+
+        double min = double.MaxValue, max = double.MinValue;
+
+        var series = seriesCache[solution];
+        for (int i = 0; i < variableValues.Count; i++) {
+          series.Points[i].SetValueXY(variableValues[i], yvalues[i]);
+          if (yvalues[i] < min) min = yvalues[i];
+          if (yvalues[i] > max) max = yvalues[i];
+        }
+        chart.Invalidate();
+
+        cancellationToken.ThrowIfCancellationRequested();
+
+        var confidenceBoundSolution = solution as IConfidenceRegressionSolution;
+        if (confidenceBoundSolution != null) {
+          var confidenceIntervalSeries = ciSeriesCache[solution];
+          var variances = confidenceBoundSolution.Model.GetEstimatedVariances(internalDataset, Enumerable.Range(0, internalDataset.Rows)).ToList();
+          for (int i = 0; i < variableValues.Count; i++) {
+            var lower = yvalues[i] - 1.96 * Math.Sqrt(variances[i]);
+            var upper = yvalues[i] + 1.96 * Math.Sqrt(variances[i]);
+            confidenceIntervalSeries.Points[i].SetValueXY(variableValues[i], lower, upper, yvalues[i], yvalues[i], yvalues[i]);
+            if (lower < min) min = lower;
+            if (upper > max) max = upper;
+          }
+          chart.Invalidate();
+        }
+
+        cancellationToken.ThrowIfCancellationRequested();
+        return new DoubleLimit(min, max);
+      }, cancellationToken);
+    }
+
+    private void InitSeriesData() {
+      if (internalDataset == null)
+        return;
+
+      foreach (var solution in solutions)
+        InitSeriesData(solution, variableValues);
+    }
+
+    private void InitSeriesData(IRegressionSolution solution, IList<string> values) {
+
+      var series = seriesCache[solution];
+      series.Points.SuspendUpdates();
+      series.Points.Clear();
+      for (int i = 0; i < values.Count; i++) {
+        series.Points.AddXY(values[i], 0.0);
+        series.Points.Last().ToolTip = values[i];
+      }
+
+      UpdateAllSeriesStyles(variableValues.IndexOf(sharedFixedVariables.GetStringValue(FreeVariable, 0)));
+      series.Points.ResumeUpdates();
+
+      Series confidenceIntervalSeries;
+      if (ciSeriesCache.TryGetValue(solution, out confidenceIntervalSeries)) {
+        confidenceIntervalSeries.Points.SuspendUpdates();
+        confidenceIntervalSeries.Points.Clear();
+        for (int i = 0; i < values.Count; i++)
+          confidenceIntervalSeries.Points.AddXY(values[i], 0.0, 0.0, 0.0, 0.0, 0.0);
+        confidenceIntervalSeries.Points.ResumeUpdates();
+      }
+    }
+
+    public async Task AddSolutionAsync(IRegressionSolution solution) {
+      if (!SolutionsCompatible(solutions.Concat(new[] { solution })))
+        throw new ArgumentException("The solution is not compatible with the problem data.");
+      if (solutions.Contains(solution))
+        return;
+
+      solutions.Add(solution);
+
+      var series = CreateSeries(solution);
+      seriesCache.Add(solution, series.Item1);
+      if (series.Item2 != null)
+        ciSeriesCache.Add(solution, series.Item2);
+
+      InitSeriesData(solution, variableValues);
+      OrderAndColorSeries();
+
+      await RecalculateAsync();
+      var args = new EventArgs<IRegressionSolution>(solution);
+      OnSolutionAdded(this, args);
+    }
+
+    public async Task RemoveSolutionAsync(IRegressionSolution solution) {
+      throw new NotSupportedException();
+    }
+
+    private static bool SolutionsCompatible(IEnumerable<IRegressionSolution> solutions) {
+      var refSolution = solutions.First();
+      var refSolVars = refSolution.ProblemData.Dataset.VariableNames;
+      foreach (var solution in solutions.Skip(1)) {
+        var variables1 = solution.ProblemData.Dataset.VariableNames;
+        if (!variables1.All(refSolVars.Contains))
+          return false;
+
+        foreach (var factorVar in variables1.Where(solution.ProblemData.Dataset.VariableHasType<string>)) {
+          var distinctVals = refSolution.ProblemData.Dataset.GetStringValues(factorVar).Distinct();
+          if (solution.ProblemData.Dataset.GetStringValues(factorVar).Any(val => !distinctVals.Contains(val))) return false;
+        }
+      }
+      return true;
+    }
+
+    #region Events
+    public event EventHandler<EventArgs<IRegressionSolution>> SolutionAdded;
+    public void OnSolutionAdded(object sender, EventArgs<IRegressionSolution> args) {
+      var added = SolutionAdded;
+      if (added == null) return;
+      added(sender, args);
+    }
+
+    public event EventHandler<EventArgs<IRegressionSolution>> SolutionRemoved;
+    public void OnSolutionRemoved(object sender, EventArgs<IRegressionSolution> args) {
+      var removed = SolutionRemoved;
+      if (removed == null) return;
+      removed(sender, args);
+    }
+
+    public event EventHandler VariableValueChanged;
+    public void OnVariableValueChanged(object sender, EventArgs args) {
+      var changed = VariableValueChanged;
+      if (changed == null) return;
+      changed(sender, args);
+    }
+
+    public event EventHandler ZoomChanged;
+    public void OnZoomChanged(object sender, EventArgs args) {
+      var changed = ZoomChanged;
+      if (changed == null) return;
+      changed(sender, args);
+    }
+
+    private void sharedFixedVariables_ItemChanged(object o, EventArgs<int, int> e) {
+      if (o != sharedFixedVariables) return;
+      var variables = sharedFixedVariables.VariableNames.ToList();
+      var rowIndex = e.Value;
+      var columnIndex = e.Value2;
+
+      var variableName = variables[columnIndex];
+      if (variableName == FreeVariable) return;
+      if (internalDataset.VariableHasType<double>(variableName)) {
+        var v = sharedFixedVariables.GetDoubleValue(variableName, rowIndex);
+        var values = new List<double>(Enumerable.Repeat(v, internalDataset.Rows));
+        internalDataset.ReplaceVariable(variableName, values);
+      } else if (internalDataset.VariableHasType<string>(variableName)) {
+        var v = sharedFixedVariables.GetStringValue(variableName, rowIndex);
+        var values = new List<String>(Enumerable.Repeat(v, internalDataset.Rows));
+        internalDataset.ReplaceVariable(variableName, values);
+      } else {
+        // unsupported type 
+        throw new NotSupportedException();
+      }
+    }
+
+    private async void chart_DragDrop(object sender, DragEventArgs e) {
+      var data = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
+      if (data != null) {
+        var solution = data as IRegressionSolution;
+        if (!solutions.Contains(solution))
+          await AddSolutionAsync(solution);
+      }
+    }
+    private void chart_DragEnter(object sender, DragEventArgs e) {
+      if (!e.Data.GetDataPresent(HeuristicLab.Common.Constants.DragDropDataFormat)) return;
+      e.Effect = DragDropEffects.None;
+
+      var data = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
+      var regressionSolution = data as IRegressionSolution;
+      if (regressionSolution != null) {
+        e.Effect = DragDropEffects.Copy;
+      }
+    }
+
+    private void calculationPendingTimer_Tick(object sender, EventArgs e) {
+      calculationPendingLabel.Visible = true;
+      Update();
+    }
+
+    private void chart_SelectionRangeChanged(object sender, CursorEventArgs e) {
+      OnZoomChanged(this, EventArgs.Empty);
+    }
+
+    private void chart_Resize(object sender, EventArgs e) {
+      UpdateTitlePosition();
+    }
+
+    private void chart_PostPaint(object sender, ChartPaintEventArgs e) {
+      if (ChartPostPaint != null)
+        ChartPostPaint(this, EventArgs.Empty);
+    }
+    #endregion
+
+    private void chart_MouseClick(object sender, MouseEventArgs e) {
+      var hitTestResult = chart.HitTest(e.X, e.Y, ChartElementType.DataPoint);
+      if (hitTestResult != null && hitTestResult.ChartElementType == ChartElementType.DataPoint) {
+        var series = hitTestResult.Series;
+        var dataPoint = (DataPoint)hitTestResult.Object;
+        var idx = series.Points.IndexOf(dataPoint);
+        UpdateSelectedValue(variableValues[idx]);
+
+        UpdateAllSeriesStyles(idx);
+      }
+    }
+
+    private void UpdateAllSeriesStyles(int selectedValueIndex) {
+      if (ShowCursor) {
+        chart.Titles[0].Text = FreeVariable + " : " + variableValues[selectedValueIndex];
+        chart.Update();
+      }
+      foreach (var s in seriesCache.Values) {
+        if (s.ChartType == SeriesChartType.Column)
+          for (int i = 0; i < s.Points.Count; i++) {
+            if (i != selectedValueIndex) {
+              s.Points[i].BorderDashStyle = ChartDashStyle.NotSet;
+            } else {
+              s.Points[i].BorderDashStyle = ChartDashStyle.Dash;
+              s.Points[i].BorderColor = Color.Red;
+            }
+          }
+      }
+    }
+
+    private void UpdateSelectedValue(string variableValue) {
+      sharedFixedVariables.SetVariableValue(variableValue, FreeVariable, 0);
+      OnVariableValueChanged(this, EventArgs.Empty);
+    }
+  }
+}
+
Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/GradientChart.Designer.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/GradientChart.Designer.cs	(revision 15131)
+++ 	(revision )
@@ -1,144 +1,0 @@
-﻿namespace HeuristicLab.Problems.DataAnalysis.Views {
-  partial class GradientChart {
-    /// <summary> 
-    /// Required designer variable.
-    /// </summary>
-    private System.ComponentModel.IContainer components = null;
-
-    /// <summary> 
-    /// Clean up any resources being used.
-    /// </summary>
-    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
-    protected override void Dispose(bool disposing) {
-      if (disposing && (components != null)) {
-        components.Dispose();
-      }
-      base.Dispose(disposing);
-    }
-
-    #region Component Designer generated code
-
-    /// <summary> 
-    /// Required method for Designer support - do not modify 
-    /// the contents of this method with the code editor.
-    /// </summary>
-    private void InitializeComponent() {
-      this.components = new System.ComponentModel.Container();
-      System.Windows.Forms.DataVisualization.Charting.VerticalLineAnnotation verticalLineAnnotation1 = new System.Windows.Forms.DataVisualization.Charting.VerticalLineAnnotation();
-      System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
-      System.Windows.Forms.DataVisualization.Charting.StripLine stripLine1 = new System.Windows.Forms.DataVisualization.Charting.StripLine();
-      System.Windows.Forms.DataVisualization.Charting.StripLine stripLine2 = new System.Windows.Forms.DataVisualization.Charting.StripLine();
-      System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
-      System.Windows.Forms.DataVisualization.Charting.Title title1 = new System.Windows.Forms.DataVisualization.Charting.Title();
-      this.calculationPendingLabel = new System.Windows.Forms.Label();
-      this.calculationPendingTimer = new System.Windows.Forms.Timer(this.components);
-      this.chart = new HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart();
-      this.configurationButton = new System.Windows.Forms.Button();
-      this.toolTip = new System.Windows.Forms.ToolTip(this.components);
-      ((System.ComponentModel.ISupportInitialize)(this.chart)).BeginInit();
-      this.SuspendLayout();
-      // 
-      // calculationPendingLabel
-      // 
-      this.calculationPendingLabel.BackColor = System.Drawing.Color.White;
-      this.calculationPendingLabel.Image = HeuristicLab.Common.Resources.VSImageLibrary.Timer;
-      this.calculationPendingLabel.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
-      this.calculationPendingLabel.Location = new System.Drawing.Point(3, 3);
-      this.calculationPendingLabel.Margin = new System.Windows.Forms.Padding(0);
-      this.calculationPendingLabel.Name = "calculationPendingLabel";
-      this.calculationPendingLabel.Size = new System.Drawing.Size(17, 17);
-      this.calculationPendingLabel.TabIndex = 1;
-      this.calculationPendingLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
-      this.calculationPendingLabel.Visible = false;
-      // 
-      // calculationPendingTimer
-      // 
-      this.calculationPendingTimer.Tick += new System.EventHandler(this.calculationPendingTimer_Tick);
-      // 
-      // chart
-      // 
-      this.chart.AllowDrop = true;
-      verticalLineAnnotation1.AllowMoving = true;
-      verticalLineAnnotation1.AxisXName = "ChartArea\\rX";
-      verticalLineAnnotation1.ClipToChartArea = "ChartArea";
-      verticalLineAnnotation1.IsInfinitive = true;
-      verticalLineAnnotation1.LineColor = System.Drawing.Color.Red;
-      verticalLineAnnotation1.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
-      verticalLineAnnotation1.Name = "VerticalLineAnnotation";
-      verticalLineAnnotation1.YAxisName = "ChartArea\\rY";
-      this.chart.Annotations.Add(verticalLineAnnotation1);
-      stripLine1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(223)))), ((int)(((byte)(58)))), ((int)(((byte)(2)))));
-      stripLine2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(223)))), ((int)(((byte)(58)))), ((int)(((byte)(2)))));
-      chartArea1.AxisX.StripLines.Add(stripLine1);
-      chartArea1.AxisX.StripLines.Add(stripLine2);
-      chartArea1.Name = "ChartArea";
-      chartArea1.Position.Auto = false;
-      chartArea1.Position.Height = 90F;
-      chartArea1.Position.Width = 100F;
-      chartArea1.Position.Y = 10F;
-      this.chart.ChartAreas.Add(chartArea1);
-      this.chart.Dock = System.Windows.Forms.DockStyle.Fill;
-      legend1.Alignment = System.Drawing.StringAlignment.Center;
-      legend1.Docking = System.Windows.Forms.DataVisualization.Charting.Docking.Top;
-      legend1.LegendItemOrder = System.Windows.Forms.DataVisualization.Charting.LegendItemOrder.ReversedSeriesOrder;
-      legend1.LegendStyle = System.Windows.Forms.DataVisualization.Charting.LegendStyle.Row;
-      legend1.Name = "Default";
-      this.chart.Legends.Add(legend1);
-      this.chart.Location = new System.Drawing.Point(0, 0);
-      this.chart.Name = "chart";
-      this.chart.Size = new System.Drawing.Size(453, 308);
-      this.chart.TabIndex = 0;
-      title1.Alignment = System.Drawing.ContentAlignment.TopCenter;
-      title1.DockedToChartArea = "ChartArea";
-      title1.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
-      title1.IsDockedInsideChartArea = false;
-      title1.Name = "Title";
-      title1.Text = "[Title]";
-      this.chart.Titles.Add(title1);
-      this.chart.SelectionRangeChanged += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.CursorEventArgs>(this.chart_SelectionRangeChanged);
-      this.chart.PostPaint += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.ChartPaintEventArgs>(this.chart_PostPaint);
-      this.chart.AnnotationPositionChanged += new System.EventHandler(this.chart_AnnotationPositionChanged);
-      this.chart.AnnotationPositionChanging += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.AnnotationPositionChangingEventArgs>(this.chart_AnnotationPositionChanging);
-      this.chart.DragDrop += new System.Windows.Forms.DragEventHandler(this.chart_DragDrop);
-      this.chart.DragEnter += new System.Windows.Forms.DragEventHandler(this.chart_DragEnter);
-      this.chart.MouseMove += new System.Windows.Forms.MouseEventHandler(this.chart_MouseMove);
-      this.chart.Resize += new System.EventHandler(this.chart_Resize);
-      // 
-      // configurationButton
-      // 
-      this.configurationButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
-      this.configurationButton.AutoSize = true;
-      this.configurationButton.Image = HeuristicLab.Common.Resources.VSImageLibrary.Properties;
-      this.configurationButton.Location = new System.Drawing.Point(426, 3);
-      this.configurationButton.Name = "configurationButton";
-      this.configurationButton.Size = new System.Drawing.Size(24, 24);
-      this.configurationButton.TabIndex = 2;
-      this.configurationButton.TabStop = false;
-      this.toolTip.SetToolTip(this.configurationButton, "Configuration");
-      this.configurationButton.UseVisualStyleBackColor = true;
-      this.configurationButton.Click += new System.EventHandler(this.config_Click);
-      // 
-      // GradientChart
-      // 
-      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-      this.Controls.Add(this.configurationButton);
-      this.Controls.Add(this.calculationPendingLabel);
-      this.Controls.Add(this.chart);
-      this.Name = "GradientChart";
-      this.Size = new System.Drawing.Size(453, 308);
-      ((System.ComponentModel.ISupportInitialize)(this.chart)).EndInit();
-      this.ResumeLayout(false);
-      this.PerformLayout();
-
-    }
-
-    #endregion
-
-    private HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart chart;
-    private System.Windows.Forms.Label calculationPendingLabel;
-    private System.Windows.Forms.Timer calculationPendingTimer;
-    private System.Windows.Forms.Button configurationButton;
-    private System.Windows.Forms.ToolTip toolTip;
-  }
-}
Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/GradientChart.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/GradientChart.cs	(revision 15131)
+++ 	(revision )
@@ -1,715 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Globalization;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-using System.Windows.Forms.DataVisualization.Charting;
-using HeuristicLab.Common;
-using HeuristicLab.MainForm.WindowsForms;
-using HeuristicLab.Visualization.ChartControlsExtensions;
-
-namespace HeuristicLab.Problems.DataAnalysis.Views {
-  public partial class GradientChart : UserControl, IGradientChart {
-    private ModifiableDataset sharedFixedVariables; // used for syncronising variable values between charts
-    private ModifiableDataset internalDataset; // holds the x values for each point drawn
-
-    private CancellationTokenSource cancelCurrentRecalculateSource;
-
-    private readonly List<IRegressionSolution> solutions;
-    private readonly Dictionary<IRegressionSolution, Series> seriesCache;
-    private readonly Dictionary<IRegressionSolution, Series> ciSeriesCache;
-
-    private readonly ToolStripMenuItem configToolStripMenuItem;
-    private readonly GradientChartConfigurationDialog configurationDialog;
-
-    #region Properties
-    public string XAxisTitle {
-      get { return chart.ChartAreas[0].AxisX.Title; }
-      set { chart.ChartAreas[0].AxisX.Title = value; }
-    }
-
-    public string YAxisTitle {
-      get { return chart.ChartAreas[0].AxisY.Title; }
-      set { chart.ChartAreas[0].AxisY.Title = value; }
-    }
-
-    public bool ShowLegend {
-      get { return chart.Legends[0].Enabled; }
-      set { chart.Legends[0].Enabled = value; }
-    }
-    public bool ShowCursor {
-      get { return chart.Annotations[0].Visible; }
-      set {
-        chart.Annotations[0].Visible = value;
-        if (!value) chart.Titles[0].Text = string.Empty;
-      }
-    }
-
-    public bool ShowConfigButton {
-      get { return configurationButton.Visible; }
-      set { configurationButton.Visible = value; }
-    }
-
-    private int xAxisTicks = 5;
-    public int XAxisTicks {
-      get { return xAxisTicks; }
-      set {
-        if (value != xAxisTicks) {
-          xAxisTicks = value;
-          SetupAxis(chart.ChartAreas[0].AxisX, trainingMin, trainingMax, XAxisTicks, FixedXAxisMin, FixedXAxisMax);
-          RecalculateInternalDataset();
-        }
-      }
-    }
-    private double? fixedXAxisMin;
-    public double? FixedXAxisMin {
-      get { return fixedXAxisMin; }
-      set {
-        if ((value.HasValue && fixedXAxisMin.HasValue && !value.Value.IsAlmost(fixedXAxisMin.Value)) || (value.HasValue != fixedXAxisMin.HasValue)) {
-          fixedXAxisMin = value;
-          if (trainingMin < trainingMax) {
-            SetupAxis(chart.ChartAreas[0].AxisX, trainingMin, trainingMax, XAxisTicks, FixedXAxisMin, FixedXAxisMax);
-            RecalculateInternalDataset();
-            // set the vertical line position 
-            if (VerticalLineAnnotation.X <= fixedXAxisMin) {
-              var axisX = chart.ChartAreas[0].AxisX;
-              var step = (axisX.Maximum - axisX.Minimum) / drawingSteps;
-              VerticalLineAnnotation.X = axisX.Minimum + step;
-            }
-          }
-        }
-      }
-    }
-    private double? fixedXAxisMax;
-    public double? FixedXAxisMax {
-      get { return fixedXAxisMax; }
-      set {
-        if ((value.HasValue && fixedXAxisMax.HasValue && !value.Value.IsAlmost(fixedXAxisMax.Value)) || (value.HasValue != fixedXAxisMax.HasValue)) {
-          fixedXAxisMax = value;
-          if (trainingMin < trainingMax) {
-            SetupAxis(chart.ChartAreas[0].AxisX, trainingMin, trainingMax, XAxisTicks, FixedXAxisMin, FixedXAxisMax);
-            RecalculateInternalDataset();
-            // set the vertical line position 
-            if (VerticalLineAnnotation.X >= fixedXAxisMax) {
-              var axisX = chart.ChartAreas[0].AxisX;
-              var step = (axisX.Maximum - axisX.Minimum) / drawingSteps;
-              VerticalLineAnnotation.X = axisX.Maximum - step;
-            }
-          }
-        }
-      }
-    }
-
-    private int yAxisTicks = 5;
-    public int YAxisTicks {
-      get { return yAxisTicks; }
-      set {
-        if (value != yAxisTicks) {
-          yAxisTicks = value;
-          SetupAxis(chart.ChartAreas[0].AxisY, yMin, yMax, YAxisTicks, FixedYAxisMin, FixedYAxisMax);
-          RecalculateInternalDataset();
-        }
-      }
-    }
-    private double? fixedYAxisMin;
-    public double? FixedYAxisMin {
-      get { return fixedYAxisMin; }
-      set {
-        if ((value.HasValue && fixedYAxisMin.HasValue && !value.Value.IsAlmost(fixedYAxisMin.Value)) || (value.HasValue != fixedYAxisMin.HasValue)) {
-          fixedYAxisMin = value;
-          SetupAxis(chart.ChartAreas[0].AxisY, yMin, yMax, YAxisTicks, FixedYAxisMin, FixedYAxisMax);
-        }
-      }
-    }
-    private double? fixedYAxisMax;
-    public double? FixedYAxisMax {
-      get { return fixedYAxisMax; }
-      set {
-        if ((value.HasValue && fixedYAxisMax.HasValue && !value.Value.IsAlmost(fixedYAxisMax.Value)) || (value.HasValue != fixedYAxisMax.HasValue)) {
-          fixedYAxisMax = value;
-          SetupAxis(chart.ChartAreas[0].AxisY, yMin, yMax, YAxisTicks, FixedYAxisMin, FixedYAxisMax);
-        }
-      }
-    }
-
-    private double trainingMin = 1;
-    private double trainingMax = -1;
-
-    private int drawingSteps = 1000;
-    public int DrawingSteps {
-      get { return drawingSteps; }
-      set {
-        if (value != drawingSteps) {
-          drawingSteps = value;
-          RecalculateInternalDataset();
-          ResizeAllSeriesData();
-        }
-      }
-    }
-
-    private string freeVariable;
-    public string FreeVariable {
-      get { return freeVariable; }
-      set {
-        if (value == freeVariable) return;
-        if (solutions.Any(s => !s.ProblemData.Dataset.DoubleVariables.Contains(value))) {
-          throw new ArgumentException("Variable does not exist in the ProblemData of the Solutions.");
-        }
-        freeVariable = value;
-        RecalculateInternalDataset();
-      }
-    }
-
-    private double yMin;
-    public double YMin {
-      get { return yMin; }
-    }
-    private double yMax;
-    public double YMax {
-      get { return yMax; }
-    }
-
-    public bool IsZoomed {
-      get { return chart.ChartAreas[0].AxisX.ScaleView.IsZoomed; }
-    }
-
-    private VerticalLineAnnotation VerticalLineAnnotation {
-      get { return (VerticalLineAnnotation)chart.Annotations.SingleOrDefault(x => x is VerticalLineAnnotation); }
-    }
-
-    internal ElementPosition InnerPlotPosition {
-      get { return chart.ChartAreas[0].InnerPlotPosition; }
-    }
-    #endregion
-
-    public event EventHandler ChartPostPaint;
-
-    public GradientChart() {
-      InitializeComponent();
-
-      solutions = new List<IRegressionSolution>();
-      seriesCache = new Dictionary<IRegressionSolution, Series>();
-      ciSeriesCache = new Dictionary<IRegressionSolution, Series>();
-
-      // Configure axis
-      chart.CustomizeAllChartAreas();
-      chart.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
-      chart.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
-      chart.ChartAreas[0].CursorX.Interval = 0;
-
-      chart.ChartAreas[0].CursorY.IsUserSelectionEnabled = true;
-      chart.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
-      chart.ChartAreas[0].CursorY.Interval = 0;
-
-      configToolStripMenuItem = new ToolStripMenuItem("Configuration");
-      configToolStripMenuItem.Click += config_Click;
-      chart.ContextMenuStrip.Items.Add(new ToolStripSeparator());
-      chart.ContextMenuStrip.Items.Add(configToolStripMenuItem);
-      configurationDialog = new GradientChartConfigurationDialog(this);
-
-      Disposed += GradientChart_Disposed;
-    }
-
-    private void GradientChart_Disposed(object sender, EventArgs e) {
-      if (cancelCurrentRecalculateSource != null)
-        cancelCurrentRecalculateSource.Cancel();
-    }
-
-    public void Configure(IEnumerable<IRegressionSolution> solutions, ModifiableDataset sharedFixedVariables, string freeVariable, int drawingSteps, bool initializeAxisRanges = true) {
-      if (!SolutionsCompatible(solutions))
-        throw new ArgumentException("Solutions are not compatible with the problem data.");
-      this.freeVariable = freeVariable;
-      this.drawingSteps = drawingSteps;
-
-      this.solutions.Clear();
-      this.solutions.AddRange(solutions);
-
-      // add an event such that whenever a value is changed in the shared dataset, 
-      // this change is reflected in the internal dataset (where the value becomes a whole column)
-      if (this.sharedFixedVariables != null)
-        this.sharedFixedVariables.ItemChanged -= sharedFixedVariables_ItemChanged;
-      this.sharedFixedVariables = sharedFixedVariables;
-      this.sharedFixedVariables.ItemChanged += sharedFixedVariables_ItemChanged;
-
-      RecalculateTrainingLimits(initializeAxisRanges);
-      RecalculateInternalDataset();
-
-      chart.Series.Clear();
-      seriesCache.Clear();
-      ciSeriesCache.Clear();
-      foreach (var solution in this.solutions) {
-        var series = CreateSeries(solution);
-        seriesCache.Add(solution, series.Item1);
-        if (series.Item2 != null)
-          ciSeriesCache.Add(solution, series.Item2);
-      }
-
-      // Set cursor and x-axis
-      // Make sure to allow a small offset to be able to distinguish the vertical line annotation from the axis
-      var defaultValue = sharedFixedVariables.GetDoubleValue(freeVariable, 0);
-      var step = (trainingMax - trainingMin) / drawingSteps;
-      var minimum = chart.ChartAreas[0].AxisX.Minimum;
-      var maximum = chart.ChartAreas[0].AxisX.Maximum;
-      if (defaultValue <= minimum)
-        VerticalLineAnnotation.X = minimum + step;
-      else if (defaultValue >= maximum)
-        VerticalLineAnnotation.X = maximum - step;
-      else
-        VerticalLineAnnotation.X = defaultValue;
-
-      if (ShowCursor)
-        chart.Titles[0].Text = FreeVariable + " : " + defaultValue.ToString("G5", CultureInfo.CurrentCulture);
-
-      ResizeAllSeriesData();
-      OrderAndColorSeries();
-    }
-
-    public async Task RecalculateAsync(bool updateOnFinish = true, bool resetYAxis = true) {
-      if (IsDisposed
-        || sharedFixedVariables == null || !solutions.Any() || string.IsNullOrEmpty(freeVariable)
-        || trainingMin.IsAlmost(trainingMax) || trainingMin > trainingMax || drawingSteps == 0)
-        return;
-
-      calculationPendingTimer.Start();
-
-      // cancel previous recalculate call
-      if (cancelCurrentRecalculateSource != null)
-        cancelCurrentRecalculateSource.Cancel();
-      cancelCurrentRecalculateSource = new CancellationTokenSource();
-      var cancellationToken = cancelCurrentRecalculateSource.Token;
-
-      // Update series
-      try {
-        var limits = await UpdateAllSeriesDataAsync(cancellationToken);
-
-        yMin = limits.Lower;
-        yMax = limits.Upper;
-        // Set y-axis
-        if (resetYAxis)
-          SetupAxis(chart.ChartAreas[0].AxisY, yMin, yMax, YAxisTicks, FixedYAxisMin, FixedYAxisMax);
-
-        UpdateOutOfTrainingRangeStripLines();
-
-        calculationPendingTimer.Stop();
-        calculationPendingLabel.Visible = false;
-        if (updateOnFinish)
-          Update();
-      } catch (OperationCanceledException) { } catch (AggregateException ae) {
-        if (!ae.InnerExceptions.Any(e => e is OperationCanceledException))
-          throw;
-      }
-    }
-
-    public void UpdateTitlePosition() {
-      var title = chart.Titles[0];
-      var plotArea = InnerPlotPosition;
-
-      title.Visible = plotArea.Width != 0;
-
-      title.Position.X = plotArea.X + (plotArea.Width / 2);
-    }
-
-    private void SetupAxis(Axis axis, double minValue, double maxValue, int ticks, double? fixedAxisMin, double? fixedAxisMax) {
-      if (minValue < maxValue) {
-        double axisMin, axisMax, axisInterval;
-        ChartUtil.CalculateAxisInterval(minValue, maxValue, ticks, out axisMin, out axisMax, out axisInterval);
-        axis.Minimum = fixedAxisMin ?? axisMin;
-        axis.Maximum = fixedAxisMax ?? axisMax;
-        axis.Interval = (axis.Maximum - axis.Minimum) / ticks;
-      }
-
-      try {
-        chart.ChartAreas[0].RecalculateAxesScale();
-      } catch (InvalidOperationException) {
-        // Can occur if eg. axis min == axis max
-      }
-    }
-
-    private void RecalculateTrainingLimits(bool initializeAxisRanges) {
-      trainingMin = solutions.Select(s => s.ProblemData.Dataset.GetDoubleValues(freeVariable, s.ProblemData.TrainingIndices).Min()).Max();
-      trainingMax = solutions.Select(s => s.ProblemData.Dataset.GetDoubleValues(freeVariable, s.ProblemData.TrainingIndices).Max()).Min();
-
-      if (initializeAxisRanges) {
-        double xmin, xmax, xinterval;
-        ChartUtil.CalculateAxisInterval(trainingMin, trainingMax, XAxisTicks, out xmin, out xmax, out xinterval);
-        FixedXAxisMin = xmin;
-        FixedXAxisMax = xmax;
-      }
-    }
-
-    private void RecalculateInternalDataset() {
-      if (sharedFixedVariables == null)
-        return;
-
-      // we expand the range in order to get nice tick intervals on the x axis
-      double xmin, xmax, xinterval;
-      ChartUtil.CalculateAxisInterval(trainingMin, trainingMax, XAxisTicks, out xmin, out xmax, out xinterval);
-
-      if (FixedXAxisMin.HasValue) xmin = FixedXAxisMin.Value;
-      if (FixedXAxisMax.HasValue) xmax = FixedXAxisMax.Value;
-      double step = (xmax - xmin) / drawingSteps;
-
-      var xvalues = new List<double>();
-      for (int i = 0; i < drawingSteps; i++)
-        xvalues.Add(xmin + i * step);
-
-      if (sharedFixedVariables == null)
-        return;
-
-      var variables = sharedFixedVariables.VariableNames.ToList();
-      var values = new List<IList>();
-      foreach (var varName in variables) {
-        if (varName == FreeVariable) {
-          values.Add(xvalues);
-        } else if (sharedFixedVariables.VariableHasType<double>(varName)) {
-          values.Add(Enumerable.Repeat(sharedFixedVariables.GetDoubleValue(varName, 0), xvalues.Count).ToList());
-        } else if (sharedFixedVariables.VariableHasType<string>(varName)) {
-          values.Add(Enumerable.Repeat(sharedFixedVariables.GetStringValue(varName, 0), xvalues.Count).ToList());
-        }
-      }
-
-      internalDataset = new ModifiableDataset(variables, values);
-    }
-
-    private Tuple<Series, Series> CreateSeries(IRegressionSolution solution) {
-      var series = new Series {
-        ChartType = SeriesChartType.Line,
-        Name = solution.ProblemData.TargetVariable + " " + solutions.IndexOf(solution)
-      };
-      series.LegendText = series.Name;
-
-      var confidenceBoundSolution = solution as IConfidenceRegressionSolution;
-      Series confidenceIntervalSeries = null;
-      if (confidenceBoundSolution != null) {
-        confidenceIntervalSeries = new Series {
-          ChartType = SeriesChartType.Range,
-          YValuesPerPoint = 2,
-          Name = "95% Conf. Interval " + series.Name,
-          IsVisibleInLegend = false
-        };
-      }
-      return Tuple.Create(series, confidenceIntervalSeries);
-    }
-
-    private void OrderAndColorSeries() {
-      chart.SuspendRepaint();
-
-      chart.Series.Clear();
-      // Add mean series for applying palette colors
-      foreach (var solution in solutions) {
-        chart.Series.Add(seriesCache[solution]);
-      }
-
-      chart.Palette = ChartColorPalette.BrightPastel;
-      chart.ApplyPaletteColors();
-      chart.Palette = ChartColorPalette.None;
-
-      // Add confidence interval series before its coresponding series for correct z index
-      foreach (var solution in solutions) {
-        Series ciSeries;
-        if (ciSeriesCache.TryGetValue(solution, out ciSeries)) {
-          var series = seriesCache[solution];
-          ciSeries.Color = Color.FromArgb(40, series.Color);
-          int idx = chart.Series.IndexOf(seriesCache[solution]);
-          chart.Series.Insert(idx, ciSeries);
-        }
-      }
-
-      chart.ResumeRepaint(true);
-    }
-
-    private async Task<DoubleLimit> UpdateAllSeriesDataAsync(CancellationToken cancellationToken) {
-      var updateTasks = solutions.Select(solution => UpdateSeriesDataAsync(solution, cancellationToken));
-
-      double min = double.MaxValue, max = double.MinValue;
-      foreach (var update in updateTasks) {
-        var limit = await update;
-        if (limit.Lower < min) min = limit.Lower;
-        if (limit.Upper > max) max = limit.Upper;
-      }
-
-      return new DoubleLimit(min, max);
-    }
-
-    private Task<DoubleLimit> UpdateSeriesDataAsync(IRegressionSolution solution, CancellationToken cancellationToken) {
-      return Task.Run(() => {
-        var xvalues = internalDataset.GetDoubleValues(FreeVariable).ToList();
-        var yvalues = solution.Model.GetEstimatedValues(internalDataset, Enumerable.Range(0, internalDataset.Rows)).ToList();
-
-        double min = double.MaxValue, max = double.MinValue;
-
-        var series = seriesCache[solution];
-        for (int i = 0; i < xvalues.Count; i++) {
-          series.Points[i].SetValueXY(xvalues[i], yvalues[i]);
-          if (yvalues[i] < min) min = yvalues[i];
-          if (yvalues[i] > max) max = yvalues[i];
-        }
-        chart.Invalidate();
-
-        cancellationToken.ThrowIfCancellationRequested();
-
-        var confidenceBoundSolution = solution as IConfidenceRegressionSolution;
-        if (confidenceBoundSolution != null) {
-          var confidenceIntervalSeries = ciSeriesCache[solution];
-          var variances = confidenceBoundSolution.Model.GetEstimatedVariances(internalDataset, Enumerable.Range(0, internalDataset.Rows)).ToList();
-          for (int i = 0; i < xvalues.Count; i++) {
-            var lower = yvalues[i] - 1.96 * Math.Sqrt(variances[i]);
-            var upper = yvalues[i] + 1.96 * Math.Sqrt(variances[i]);
-            confidenceIntervalSeries.Points[i].SetValueXY(xvalues[i], lower, upper);
-            if (lower < min) min = lower;
-            if (upper > max) max = upper;
-          }
-          chart.Invalidate();
-        }
-
-        cancellationToken.ThrowIfCancellationRequested();
-        return new DoubleLimit(min, max);
-      }, cancellationToken);
-    }
-
-    private void ResizeAllSeriesData() {
-      if (internalDataset == null)
-        return;
-
-      var xvalues = internalDataset.GetDoubleValues(FreeVariable).ToList();
-      foreach (var solution in solutions)
-        ResizeSeriesData(solution, xvalues);
-    }
-    private void ResizeSeriesData(IRegressionSolution solution, IList<double> xvalues = null) {
-      if (xvalues == null)
-        xvalues = internalDataset.GetDoubleValues(FreeVariable).ToList();
-
-      var series = seriesCache[solution];
-      series.Points.SuspendUpdates();
-      series.Points.Clear();
-      for (int i = 0; i < xvalues.Count; i++)
-        series.Points.Add(new DataPoint(xvalues[i], 0.0));
-      series.Points.ResumeUpdates();
-
-      Series confidenceIntervalSeries;
-      if (ciSeriesCache.TryGetValue(solution, out confidenceIntervalSeries)) {
-        confidenceIntervalSeries.Points.SuspendUpdates();
-        confidenceIntervalSeries.Points.Clear();
-        for (int i = 0; i < xvalues.Count; i++)
-          confidenceIntervalSeries.Points.Add(new DataPoint(xvalues[i], new[] { -1.0, 1.0 }));
-        confidenceIntervalSeries.Points.ResumeUpdates();
-      }
-    }
-
-    public async Task AddSolutionAsync(IRegressionSolution solution) {
-      if (!SolutionsCompatible(solutions.Concat(new[] { solution })))
-        throw new ArgumentException("The solution is not compatible with the problem data.");
-      if (solutions.Contains(solution))
-        return;
-
-      solutions.Add(solution);
-      RecalculateTrainingLimits(true);
-
-      var series = CreateSeries(solution);
-      seriesCache.Add(solution, series.Item1);
-      if (series.Item2 != null)
-        ciSeriesCache.Add(solution, series.Item2);
-
-      ResizeSeriesData(solution);
-      OrderAndColorSeries();
-
-      await RecalculateAsync();
-      var args = new EventArgs<IRegressionSolution>(solution);
-      OnSolutionAdded(this, args);
-    }
-
-    public async Task RemoveSolutionAsync(IRegressionSolution solution) {
-      if (!solutions.Remove(solution))
-        return;
-
-      RecalculateTrainingLimits(true);
-
-      seriesCache.Remove(solution);
-      ciSeriesCache.Remove(solution);
-
-      await RecalculateAsync();
-      var args = new EventArgs<IRegressionSolution>(solution);
-      OnSolutionRemoved(this, args);
-    }
-
-    private static bool SolutionsCompatible(IEnumerable<IRegressionSolution> solutions) {
-      var refSolution = solutions.First();
-      var refSolVars = refSolution.ProblemData.Dataset.VariableNames;
-      foreach (var solution in solutions.Skip(1)) {
-        var variables1 = solution.ProblemData.Dataset.VariableNames;
-        if (!variables1.All(refSolVars.Contains))
-          return false;
-
-        foreach (var factorVar in variables1.Where(solution.ProblemData.Dataset.VariableHasType<string>)) {
-          var distinctVals = refSolution.ProblemData.Dataset.GetStringValues(factorVar).Distinct();
-          if (solution.ProblemData.Dataset.GetStringValues(factorVar).Any(val => !distinctVals.Contains(val))) return false;
-        }
-      }
-      return true;
-    }
-
-    private void UpdateOutOfTrainingRangeStripLines() {
-      var axisX = chart.ChartAreas[0].AxisX;
-      var lowerStripLine = axisX.StripLines[0];
-      var upperStripLine = axisX.StripLines[1];
-
-      lowerStripLine.IntervalOffset = axisX.Minimum;
-      lowerStripLine.StripWidth = Math.Abs(trainingMin - axisX.Minimum);
-
-      upperStripLine.IntervalOffset = trainingMax;
-      upperStripLine.StripWidth = Math.Abs(axisX.Maximum - trainingMax);
-    }
-
-    #region Events
-    public event EventHandler<EventArgs<IRegressionSolution>> SolutionAdded;
-    public void OnSolutionAdded(object sender, EventArgs<IRegressionSolution> args) {
-      var added = SolutionAdded;
-      if (added == null) return;
-      added(sender, args);
-    }
-
-    public event EventHandler<EventArgs<IRegressionSolution>> SolutionRemoved;
-    public void OnSolutionRemoved(object sender, EventArgs<IRegressionSolution> args) {
-      var removed = SolutionRemoved;
-      if (removed == null) return;
-      removed(sender, args);
-    }
-
-    public event EventHandler VariableValueChanged;
-    public void OnVariableValueChanged(object sender, EventArgs args) {
-      var changed = VariableValueChanged;
-      if (changed == null) return;
-      changed(sender, args);
-    }
-
-    public event EventHandler ZoomChanged;
-    public void OnZoomChanged(object sender, EventArgs args) {
-      var changed = ZoomChanged;
-      if (changed == null) return;
-      changed(sender, args);
-    }
-
-    private void sharedFixedVariables_ItemChanged(object o, EventArgs<int, int> e) {
-      if (o != sharedFixedVariables) return;
-      var variables = sharedFixedVariables.VariableNames.ToList();
-      var rowIndex = e.Value;
-      var columnIndex = e.Value2;
-
-      var variableName = variables[columnIndex];
-      if (variableName == FreeVariable) return;
-      if (internalDataset.VariableHasType<double>(variableName)) {
-        var v = sharedFixedVariables.GetDoubleValue(variableName, rowIndex);
-        var values = new List<double>(Enumerable.Repeat(v, internalDataset.Rows));
-        internalDataset.ReplaceVariable(variableName, values);
-      } else if (internalDataset.VariableHasType<string>(variableName)) {
-        var v = sharedFixedVariables.GetStringValue(variableName, rowIndex);
-        var values = new List<String>(Enumerable.Repeat(v, internalDataset.Rows));
-        internalDataset.ReplaceVariable(variableName, values);
-      } else {
-        // unsupported type 
-        throw new NotSupportedException();
-      }
-    }
-
-    private void chart_AnnotationPositionChanging(object sender, AnnotationPositionChangingEventArgs e) {
-      var step = (trainingMax - trainingMin) / drawingSteps;
-      double newLocation = step * (long)Math.Round(e.NewLocationX / step);
-      var axisX = chart.ChartAreas[0].AxisX;
-      if (newLocation >= axisX.Maximum)
-        newLocation = axisX.Maximum - step;
-      if (newLocation <= axisX.Minimum)
-        newLocation = axisX.Minimum + step;
-
-      e.NewLocationX = newLocation;
-
-      UpdateCursor();
-    }
-    private void chart_AnnotationPositionChanged(object sender, EventArgs e) {
-      UpdateCursor();
-    }
-    private void UpdateCursor() {
-      var x = VerticalLineAnnotation.X;
-      sharedFixedVariables.SetVariableValue(x, FreeVariable, 0);
-
-      if (ShowCursor) {
-        chart.Titles[0].Text = FreeVariable + " : " + x.ToString("G5", CultureInfo.CurrentCulture);
-        chart.Update();
-      }
-
-      OnVariableValueChanged(this, EventArgs.Empty);
-    }
-
-    private void chart_MouseMove(object sender, MouseEventArgs e) {
-      bool hitCursor = chart.HitTest(e.X, e.Y).ChartElementType == ChartElementType.Annotation;
-      chart.Cursor = hitCursor ? Cursors.VSplit : Cursors.Default;
-    }
-
-    private async void chart_DragDrop(object sender, DragEventArgs e) {
-      var data = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
-      if (data != null) {
-        var solution = data as IRegressionSolution;
-        if (!solutions.Contains(solution))
-          await AddSolutionAsync(solution);
-      }
-    }
-    private void chart_DragEnter(object sender, DragEventArgs e) {
-      if (!e.Data.GetDataPresent(HeuristicLab.Common.Constants.DragDropDataFormat)) return;
-      e.Effect = DragDropEffects.None;
-
-      var data = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
-      var regressionSolution = data as IRegressionSolution;
-      if (regressionSolution != null) {
-        e.Effect = DragDropEffects.Copy;
-      }
-    }
-
-    private void calculationPendingTimer_Tick(object sender, EventArgs e) {
-      calculationPendingLabel.Visible = true;
-      Update();
-    }
-
-    private void config_Click(object sender, EventArgs e) {
-      configurationDialog.ShowDialog(this);
-    }
-
-    private void chart_SelectionRangeChanged(object sender, CursorEventArgs e) {
-      OnZoomChanged(this, EventArgs.Empty);
-    }
-
-    private void chart_Resize(object sender, EventArgs e) {
-      UpdateTitlePosition();
-    }
-
-    private void chart_PostPaint(object sender, ChartPaintEventArgs e) {
-      if (ChartPostPaint != null)
-        ChartPostPaint(this, EventArgs.Empty);
-    }
-    #endregion
-  }
-}
-
Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/GradientChartConfigurationDialog.Designer.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/GradientChartConfigurationDialog.Designer.cs	(revision 15131)
+++ 	(revision )
@@ -1,327 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-namespace HeuristicLab.Problems.DataAnalysis.Views {
-  partial class GradientChartConfigurationDialog {
-    /// <summary>
-    /// Required designer variable.
-    /// </summary>
-    private System.ComponentModel.IContainer components = null;
-
-    /// <summary>
-    /// Clean up any resources being used.
-    /// </summary>
-    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
-    protected override void Dispose(bool disposing) {
-      if (disposing && (components != null)) {
-        components.Dispose();
-      }
-      base.Dispose(disposing);
-    }
-
-    #region Windows Form Designer generated code
-
-    /// <summary>
-    /// Required method for Designer support - do not modify
-    /// the contents of this method with the code editor.
-    /// </summary>
-    private void InitializeComponent() {
-      this.components = new System.ComponentModel.Container();
-      this.xAxisGroupBox = new System.Windows.Forms.GroupBox();
-      this.maxXTextBox = new System.Windows.Forms.TextBox();
-      this.xAutomaticCheckBox = new System.Windows.Forms.CheckBox();
-      this.minXTextBox = new System.Windows.Forms.TextBox();
-      this.maxXLabel = new System.Windows.Forms.Label();
-      this.minXLabel = new System.Windows.Forms.Label();
-      this.yAxisGroupBox = new System.Windows.Forms.GroupBox();
-      this.maxYTextBox = new System.Windows.Forms.TextBox();
-      this.yAutomaticCheckBox = new System.Windows.Forms.CheckBox();
-      this.minYTextBox = new System.Windows.Forms.TextBox();
-      this.maxYLabel = new System.Windows.Forms.Label();
-      this.minYLabel = new System.Windows.Forms.Label();
-      this.miscGroupBox = new System.Windows.Forms.GroupBox();
-      this.StepsNumericUpDown = new System.Windows.Forms.NumericUpDown();
-      this.stepsLabel = new System.Windows.Forms.Label();
-      this.applyButton = new System.Windows.Forms.Button();
-      this.cancelButton = new System.Windows.Forms.Button();
-      this.errorProvider = new System.Windows.Forms.ErrorProvider(this.components);
-      this.xAxisGroupBox.SuspendLayout();
-      this.yAxisGroupBox.SuspendLayout();
-      this.miscGroupBox.SuspendLayout();
-      ((System.ComponentModel.ISupportInitialize)(this.StepsNumericUpDown)).BeginInit();
-      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
-      this.SuspendLayout();
-      // 
-      // xAxisGroupBox
-      // 
-      this.xAxisGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.xAxisGroupBox.Controls.Add(this.maxXTextBox);
-      this.xAxisGroupBox.Controls.Add(this.xAutomaticCheckBox);
-      this.xAxisGroupBox.Controls.Add(this.minXTextBox);
-      this.xAxisGroupBox.Controls.Add(this.maxXLabel);
-      this.xAxisGroupBox.Controls.Add(this.minXLabel);
-      this.xAxisGroupBox.Location = new System.Drawing.Point(12, 12);
-      this.xAxisGroupBox.Name = "xAxisGroupBox";
-      this.xAxisGroupBox.Size = new System.Drawing.Size(234, 78);
-      this.xAxisGroupBox.TabIndex = 1;
-      this.xAxisGroupBox.TabStop = false;
-      this.xAxisGroupBox.Text = "X-Axis";
-      // 
-      // maxXTextBox
-      // 
-      this.maxXTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.maxXTextBox.Location = new System.Drawing.Point(61, 45);
-      this.maxXTextBox.Name = "maxXTextBox";
-      this.maxXTextBox.Size = new System.Drawing.Size(167, 20);
-      this.maxXTextBox.TabIndex = 3;
-      this.maxXTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.numberTextBox_Validating);
-      this.maxXTextBox.Validated += new System.EventHandler(this.numberTextBox_Validated);
-      // 
-      // xAutomaticCheckBox
-      // 
-      this.xAutomaticCheckBox.AutoSize = true;
-      this.xAutomaticCheckBox.Location = new System.Drawing.Point(48, -1);
-      this.xAutomaticCheckBox.Name = "xAutomaticCheckBox";
-      this.xAutomaticCheckBox.Size = new System.Drawing.Size(73, 17);
-      this.xAutomaticCheckBox.TabIndex = 1;
-      this.xAutomaticCheckBox.Text = "Automatic";
-      this.xAutomaticCheckBox.UseVisualStyleBackColor = true;
-      this.xAutomaticCheckBox.CheckedChanged += new System.EventHandler(this.automaticCheckBox_CheckedChanged);
-      // 
-      // minXTextBox
-      // 
-      this.minXTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.minXTextBox.Location = new System.Drawing.Point(61, 19);
-      this.minXTextBox.Name = "minXTextBox";
-      this.minXTextBox.Size = new System.Drawing.Size(167, 20);
-      this.minXTextBox.TabIndex = 2;
-      this.minXTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.numberTextBox_Validating);
-      this.minXTextBox.Validated += new System.EventHandler(this.numberTextBox_Validated);
-      // 
-      // maxXLabel
-      // 
-      this.maxXLabel.AutoSize = true;
-      this.maxXLabel.Location = new System.Drawing.Point(7, 48);
-      this.maxXLabel.Name = "maxXLabel";
-      this.maxXLabel.Size = new System.Drawing.Size(27, 13);
-      this.maxXLabel.TabIndex = 1;
-      this.maxXLabel.Text = "Max";
-      // 
-      // minXLabel
-      // 
-      this.minXLabel.AutoSize = true;
-      this.minXLabel.Location = new System.Drawing.Point(7, 22);
-      this.minXLabel.Name = "minXLabel";
-      this.minXLabel.Size = new System.Drawing.Size(24, 13);
-      this.minXLabel.TabIndex = 0;
-      this.minXLabel.Text = "Min";
-      // 
-      // yAxisGroupBox
-      // 
-      this.yAxisGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.yAxisGroupBox.Controls.Add(this.maxYTextBox);
-      this.yAxisGroupBox.Controls.Add(this.yAutomaticCheckBox);
-      this.yAxisGroupBox.Controls.Add(this.minYTextBox);
-      this.yAxisGroupBox.Controls.Add(this.maxYLabel);
-      this.yAxisGroupBox.Controls.Add(this.minYLabel);
-      this.yAxisGroupBox.Location = new System.Drawing.Point(13, 96);
-      this.yAxisGroupBox.Name = "yAxisGroupBox";
-      this.yAxisGroupBox.Size = new System.Drawing.Size(234, 75);
-      this.yAxisGroupBox.TabIndex = 2;
-      this.yAxisGroupBox.TabStop = false;
-      this.yAxisGroupBox.Text = "Y-Axis";
-      // 
-      // maxYTextBox
-      // 
-      this.maxYTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.maxYTextBox.Location = new System.Drawing.Point(61, 45);
-      this.maxYTextBox.Name = "maxYTextBox";
-      this.maxYTextBox.Size = new System.Drawing.Size(167, 20);
-      this.maxYTextBox.TabIndex = 3;
-      this.maxYTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.numberTextBox_Validating);
-      this.maxYTextBox.Validated += new System.EventHandler(this.numberTextBox_Validated);
-      // 
-      // yAutomaticCheckBox
-      // 
-      this.yAutomaticCheckBox.AutoSize = true;
-      this.yAutomaticCheckBox.Location = new System.Drawing.Point(47, -1);
-      this.yAutomaticCheckBox.Name = "yAutomaticCheckBox";
-      this.yAutomaticCheckBox.Size = new System.Drawing.Size(73, 17);
-      this.yAutomaticCheckBox.TabIndex = 1;
-      this.yAutomaticCheckBox.Text = "Automatic";
-      this.yAutomaticCheckBox.UseVisualStyleBackColor = true;
-      this.yAutomaticCheckBox.CheckedChanged += new System.EventHandler(this.automaticCheckBox_CheckedChanged);
-      // 
-      // minYTextBox
-      // 
-      this.minYTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.minYTextBox.Location = new System.Drawing.Point(61, 19);
-      this.minYTextBox.Name = "minYTextBox";
-      this.minYTextBox.Size = new System.Drawing.Size(167, 20);
-      this.minYTextBox.TabIndex = 2;
-      this.minYTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.numberTextBox_Validating);
-      this.minYTextBox.Validated += new System.EventHandler(this.numberTextBox_Validated);
-      // 
-      // maxYLabel
-      // 
-      this.maxYLabel.AutoSize = true;
-      this.maxYLabel.Location = new System.Drawing.Point(7, 48);
-      this.maxYLabel.Name = "maxYLabel";
-      this.maxYLabel.Size = new System.Drawing.Size(27, 13);
-      this.maxYLabel.TabIndex = 1;
-      this.maxYLabel.Text = "Max";
-      // 
-      // minYLabel
-      // 
-      this.minYLabel.AutoSize = true;
-      this.minYLabel.Location = new System.Drawing.Point(7, 22);
-      this.minYLabel.Name = "minYLabel";
-      this.minYLabel.Size = new System.Drawing.Size(24, 13);
-      this.minYLabel.TabIndex = 0;
-      this.minYLabel.Text = "Min";
-      // 
-      // miscGroupBox
-      // 
-      this.miscGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.miscGroupBox.Controls.Add(this.StepsNumericUpDown);
-      this.miscGroupBox.Controls.Add(this.stepsLabel);
-      this.miscGroupBox.Location = new System.Drawing.Point(13, 177);
-      this.miscGroupBox.Name = "miscGroupBox";
-      this.miscGroupBox.Size = new System.Drawing.Size(233, 53);
-      this.miscGroupBox.TabIndex = 4;
-      this.miscGroupBox.TabStop = false;
-      // 
-      // StepsNumericUpDown
-      // 
-      this.StepsNumericUpDown.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.StepsNumericUpDown.Increment = new decimal(new int[] {
-            50,
-            0,
-            0,
-            0});
-      this.StepsNumericUpDown.Location = new System.Drawing.Point(61, 20);
-      this.StepsNumericUpDown.Maximum = new decimal(new int[] {
-            100000,
-            0,
-            0,
-            0});
-      this.StepsNumericUpDown.Name = "StepsNumericUpDown";
-      this.StepsNumericUpDown.Size = new System.Drawing.Size(166, 20);
-      this.StepsNumericUpDown.TabIndex = 4;
-      // 
-      // stepsLabel
-      // 
-      this.stepsLabel.AutoSize = true;
-      this.stepsLabel.Location = new System.Drawing.Point(6, 22);
-      this.stepsLabel.Name = "stepsLabel";
-      this.stepsLabel.Size = new System.Drawing.Size(34, 13);
-      this.stepsLabel.TabIndex = 1;
-      this.stepsLabel.Text = "Steps";
-      // 
-      // applyButton
-      // 
-      this.applyButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
-      this.applyButton.Location = new System.Drawing.Point(91, 239);
-      this.applyButton.Name = "applyButton";
-      this.applyButton.Size = new System.Drawing.Size(75, 23);
-      this.applyButton.TabIndex = 5;
-      this.applyButton.Text = "Apply";
-      this.applyButton.UseVisualStyleBackColor = true;
-      this.applyButton.Click += new System.EventHandler(this.okButton_Click);
-      // 
-      // cancelButton
-      // 
-      this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
-      this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
-      this.cancelButton.Location = new System.Drawing.Point(172, 239);
-      this.cancelButton.Name = "cancelButton";
-      this.cancelButton.Size = new System.Drawing.Size(75, 23);
-      this.cancelButton.TabIndex = 6;
-      this.cancelButton.Text = "Cancel";
-      this.cancelButton.UseVisualStyleBackColor = true;
-      // 
-      // errorProvider
-      // 
-      this.errorProvider.BlinkStyle = System.Windows.Forms.ErrorBlinkStyle.NeverBlink;
-      this.errorProvider.ContainerControl = this;
-      // 
-      // GradientChartConfigurationDialog
-      // 
-      this.AcceptButton = this.applyButton;
-      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
-      this.CancelButton = this.cancelButton;
-      this.ClientSize = new System.Drawing.Size(258, 272);
-      this.Controls.Add(this.cancelButton);
-      this.Controls.Add(this.applyButton);
-      this.Controls.Add(this.miscGroupBox);
-      this.Controls.Add(this.xAxisGroupBox);
-      this.Controls.Add(this.yAxisGroupBox);
-      this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
-      this.MaximizeBox = false;
-      this.MinimizeBox = false;
-      this.Name = "GradientChartConfigurationDialog";
-      this.ShowIcon = false;
-      this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
-      this.Text = "Configure Gradient Chart";
-      this.TopMost = true;
-      this.Shown += new System.EventHandler(this.GradientChartConfigurationDialog_Shown);
-      this.xAxisGroupBox.ResumeLayout(false);
-      this.xAxisGroupBox.PerformLayout();
-      this.yAxisGroupBox.ResumeLayout(false);
-      this.yAxisGroupBox.PerformLayout();
-      this.miscGroupBox.ResumeLayout(false);
-      this.miscGroupBox.PerformLayout();
-      ((System.ComponentModel.ISupportInitialize)(this.StepsNumericUpDown)).EndInit();
-      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit();
-      this.ResumeLayout(false);
-
-    }
-
-    #endregion
-
-    private System.Windows.Forms.GroupBox xAxisGroupBox;
-    private System.Windows.Forms.TextBox maxXTextBox;
-    private System.Windows.Forms.TextBox minXTextBox;
-    private System.Windows.Forms.Label maxXLabel;
-    private System.Windows.Forms.Label minXLabel;
-    private System.Windows.Forms.GroupBox yAxisGroupBox;
-    private System.Windows.Forms.TextBox maxYTextBox;
-    private System.Windows.Forms.CheckBox yAutomaticCheckBox;
-    private System.Windows.Forms.TextBox minYTextBox;
-    private System.Windows.Forms.Label maxYLabel;
-    private System.Windows.Forms.Label minYLabel;
-    private System.Windows.Forms.GroupBox miscGroupBox;
-    private System.Windows.Forms.Label stepsLabel;
-    private System.Windows.Forms.Button applyButton;
-    private System.Windows.Forms.Button cancelButton;
-    private System.Windows.Forms.CheckBox xAutomaticCheckBox;
-    private System.Windows.Forms.NumericUpDown StepsNumericUpDown;
-    private System.Windows.Forms.ErrorProvider errorProvider;
-  }
-}
Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/GradientChartConfigurationDialog.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/GradientChartConfigurationDialog.cs	(revision 15131)
+++ 	(revision )
@@ -1,121 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System;
-using System.ComponentModel;
-using System.Globalization;
-using System.Windows.Forms;
-using HeuristicLab.MainForm.WindowsForms;
-
-namespace HeuristicLab.Problems.DataAnalysis.Views {
-  public partial class GradientChartConfigurationDialog : Form {
-    private readonly GradientChart chart;
-
-    public GradientChartConfigurationDialog(GradientChart chart) {
-      this.chart = chart;
-      InitializeComponent();
-    }
-
-    private void GradientChartConfigurationDialog_Shown(object sender, EventArgs e) {
-      if (chart.FixedXAxisMin.HasValue && chart.FixedXAxisMax.HasValue) {
-        xAutomaticCheckBox.Checked = false;
-        minXTextBox.Text = chart.FixedXAxisMin.Value.ToString(CultureInfo.CurrentUICulture);
-        maxXTextBox.Text = chart.FixedXAxisMax.Value.ToString(CultureInfo.CurrentUICulture);
-      } else xAutomaticCheckBox.Checked = true;
-      if (chart.FixedYAxisMin.HasValue && chart.FixedYAxisMax.HasValue) {
-        yAutomaticCheckBox.Checked = false;
-        minYTextBox.Text = chart.FixedYAxisMin.Value.ToString(CultureInfo.CurrentUICulture);
-        maxYTextBox.Text = chart.FixedYAxisMax.Value.ToString(CultureInfo.CurrentUICulture);
-      } else yAutomaticCheckBox.Checked = true;
-      StepsNumericUpDown.Value = chart.DrawingSteps;
-    }
-
-    private async void okButton_Click(object sender, System.EventArgs e) {
-      try {
-        Enabled = false;
-        chart.SuspendRepaint();
-        if (xAutomaticCheckBox.Checked) {
-          chart.FixedXAxisMin = null;
-          chart.FixedXAxisMax = null;
-        } else {
-          var min = double.Parse(minXTextBox.Text, CultureInfo.CurrentUICulture);
-          var max = double.Parse(maxXTextBox.Text, CultureInfo.CurrentUICulture);
-          chart.FixedXAxisMin = min;
-          chart.FixedXAxisMax = max;
-        }
-
-        if (yAutomaticCheckBox.Checked) {
-          chart.FixedYAxisMin = null;
-          chart.FixedYAxisMax = null;
-        } else {
-          var min = double.Parse(minYTextBox.Text, CultureInfo.CurrentUICulture);
-          var max = double.Parse(maxYTextBox.Text, CultureInfo.CurrentUICulture);
-          chart.FixedYAxisMin = min;
-          chart.FixedYAxisMax = max;
-        }
-
-        chart.DrawingSteps = (int)StepsNumericUpDown.Value;
-
-        await chart.RecalculateAsync(resetYAxis: false);
-
-        Close();
-      }
-      catch (FormatException) {
-        MessageBox.Show(this, "Illegal number format", "Wrong format", MessageBoxButtons.OK, MessageBoxIcon.Error);
-      }
-      finally {
-        Enabled = true;
-        chart.ResumeRepaint(true);
-      }
-    }
-
-    private void automaticCheckBox_CheckedChanged(object sender, EventArgs e) {
-      minXTextBox.Enabled = !xAutomaticCheckBox.Checked;
-      maxXTextBox.Enabled = !xAutomaticCheckBox.Checked;
-
-      minYTextBox.Enabled = !yAutomaticCheckBox.Checked;
-      maxYTextBox.Enabled = !yAutomaticCheckBox.Checked;
-    }
-
-    private void numberTextBox_Validating(object sender, CancelEventArgs e) {
-      var textBox = sender as TextBox;
-      if (textBox != null) {
-        double number;
-        if (!double.TryParse(textBox.Text, NumberStyles.Any, CultureInfo.CurrentUICulture, out number)) {
-          e.Cancel = true;
-          applyButton.Enabled = false;
-          errorProvider.SetIconAlignment(textBox, ErrorIconAlignment.MiddleLeft);
-          errorProvider.SetIconPadding(textBox, 2);
-          errorProvider.SetError(textBox, "Illegal number format");
-          textBox.SelectAll();
-        }
-      }
-    }
-
-    private void numberTextBox_Validated(object sender, EventArgs e) {
-      var textBox = sender as TextBox;
-      if (textBox != null) {
-        errorProvider.SetError(textBox, string.Empty);
-        applyButton.Enabled = true;
-      }
-    }
-  }
-}
Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/PartialDependencePlot.Designer.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/PartialDependencePlot.Designer.cs	(revision 15137)
+++ stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/PartialDependencePlot.Designer.cs	(revision 15137)
@@ -0,0 +1,144 @@
+﻿namespace HeuristicLab.Problems.DataAnalysis.Views {
+  partial class PartialDependencePlot {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      this.components = new System.ComponentModel.Container();
+      System.Windows.Forms.DataVisualization.Charting.VerticalLineAnnotation verticalLineAnnotation1 = new System.Windows.Forms.DataVisualization.Charting.VerticalLineAnnotation();
+      System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
+      System.Windows.Forms.DataVisualization.Charting.StripLine stripLine1 = new System.Windows.Forms.DataVisualization.Charting.StripLine();
+      System.Windows.Forms.DataVisualization.Charting.StripLine stripLine2 = new System.Windows.Forms.DataVisualization.Charting.StripLine();
+      System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
+      System.Windows.Forms.DataVisualization.Charting.Title title1 = new System.Windows.Forms.DataVisualization.Charting.Title();
+      this.calculationPendingLabel = new System.Windows.Forms.Label();
+      this.calculationPendingTimer = new System.Windows.Forms.Timer(this.components);
+      this.chart = new HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart();
+      this.configurationButton = new System.Windows.Forms.Button();
+      this.toolTip = new System.Windows.Forms.ToolTip(this.components);
+      ((System.ComponentModel.ISupportInitialize)(this.chart)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // calculationPendingLabel
+      // 
+      this.calculationPendingLabel.BackColor = System.Drawing.Color.White;
+      this.calculationPendingLabel.Image = HeuristicLab.Common.Resources.VSImageLibrary.Timer;
+      this.calculationPendingLabel.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
+      this.calculationPendingLabel.Location = new System.Drawing.Point(3, 3);
+      this.calculationPendingLabel.Margin = new System.Windows.Forms.Padding(0);
+      this.calculationPendingLabel.Name = "calculationPendingLabel";
+      this.calculationPendingLabel.Size = new System.Drawing.Size(17, 17);
+      this.calculationPendingLabel.TabIndex = 1;
+      this.calculationPendingLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+      this.calculationPendingLabel.Visible = false;
+      // 
+      // calculationPendingTimer
+      // 
+      this.calculationPendingTimer.Tick += new System.EventHandler(this.calculationPendingTimer_Tick);
+      // 
+      // chart
+      // 
+      this.chart.AllowDrop = true;
+      verticalLineAnnotation1.AllowMoving = true;
+      verticalLineAnnotation1.AxisXName = "ChartArea\\rX";
+      verticalLineAnnotation1.ClipToChartArea = "ChartArea";
+      verticalLineAnnotation1.IsInfinitive = true;
+      verticalLineAnnotation1.LineColor = System.Drawing.Color.Red;
+      verticalLineAnnotation1.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
+      verticalLineAnnotation1.Name = "VerticalLineAnnotation";
+      verticalLineAnnotation1.YAxisName = "ChartArea\\rY";
+      this.chart.Annotations.Add(verticalLineAnnotation1);
+      stripLine1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(223)))), ((int)(((byte)(58)))), ((int)(((byte)(2)))));
+      stripLine2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(223)))), ((int)(((byte)(58)))), ((int)(((byte)(2)))));
+      chartArea1.AxisX.StripLines.Add(stripLine1);
+      chartArea1.AxisX.StripLines.Add(stripLine2);
+      chartArea1.Name = "ChartArea";
+      chartArea1.Position.Auto = false;
+      chartArea1.Position.Height = 90F;
+      chartArea1.Position.Width = 100F;
+      chartArea1.Position.Y = 10F;
+      this.chart.ChartAreas.Add(chartArea1);
+      this.chart.Dock = System.Windows.Forms.DockStyle.Fill;
+      legend1.Alignment = System.Drawing.StringAlignment.Center;
+      legend1.Docking = System.Windows.Forms.DataVisualization.Charting.Docking.Top;
+      legend1.LegendItemOrder = System.Windows.Forms.DataVisualization.Charting.LegendItemOrder.ReversedSeriesOrder;
+      legend1.LegendStyle = System.Windows.Forms.DataVisualization.Charting.LegendStyle.Row;
+      legend1.Name = "Default";
+      this.chart.Legends.Add(legend1);
+      this.chart.Location = new System.Drawing.Point(0, 0);
+      this.chart.Name = "chart";
+      this.chart.Size = new System.Drawing.Size(453, 308);
+      this.chart.TabIndex = 0;
+      title1.Alignment = System.Drawing.ContentAlignment.TopCenter;
+      title1.DockedToChartArea = "ChartArea";
+      title1.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+      title1.IsDockedInsideChartArea = false;
+      title1.Name = "Title";
+      title1.Text = "[Title]";
+      this.chart.Titles.Add(title1);
+      this.chart.SelectionRangeChanged += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.CursorEventArgs>(this.chart_SelectionRangeChanged);
+      this.chart.PostPaint += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.ChartPaintEventArgs>(this.chart_PostPaint);
+      this.chart.AnnotationPositionChanged += new System.EventHandler(this.chart_AnnotationPositionChanged);
+      this.chart.AnnotationPositionChanging += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.AnnotationPositionChangingEventArgs>(this.chart_AnnotationPositionChanging);
+      this.chart.DragDrop += new System.Windows.Forms.DragEventHandler(this.chart_DragDrop);
+      this.chart.DragEnter += new System.Windows.Forms.DragEventHandler(this.chart_DragEnter);
+      this.chart.MouseMove += new System.Windows.Forms.MouseEventHandler(this.chart_MouseMove);
+      this.chart.Resize += new System.EventHandler(this.chart_Resize);
+      // 
+      // configurationButton
+      // 
+      this.configurationButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+      this.configurationButton.AutoSize = true;
+      this.configurationButton.Image = HeuristicLab.Common.Resources.VSImageLibrary.Properties;
+      this.configurationButton.Location = new System.Drawing.Point(426, 3);
+      this.configurationButton.Name = "configurationButton";
+      this.configurationButton.Size = new System.Drawing.Size(24, 24);
+      this.configurationButton.TabIndex = 2;
+      this.configurationButton.TabStop = false;
+      this.toolTip.SetToolTip(this.configurationButton, "Configuration");
+      this.configurationButton.UseVisualStyleBackColor = true;
+      this.configurationButton.Click += new System.EventHandler(this.config_Click);
+      // 
+      // PartialDependencePlot
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Controls.Add(this.configurationButton);
+      this.Controls.Add(this.calculationPendingLabel);
+      this.Controls.Add(this.chart);
+      this.Name = "PartialDependencePlot";
+      this.Size = new System.Drawing.Size(453, 308);
+      ((System.ComponentModel.ISupportInitialize)(this.chart)).EndInit();
+      this.ResumeLayout(false);
+      this.PerformLayout();
+
+    }
+
+    #endregion
+
+    private HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart chart;
+    private System.Windows.Forms.Label calculationPendingLabel;
+    private System.Windows.Forms.Timer calculationPendingTimer;
+    private System.Windows.Forms.Button configurationButton;
+    private System.Windows.Forms.ToolTip toolTip;
+  }
+}
Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/PartialDependencePlot.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/PartialDependencePlot.cs	(revision 15137)
+++ stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/PartialDependencePlot.cs	(revision 15137)
@@ -0,0 +1,715 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Globalization;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using System.Windows.Forms.DataVisualization.Charting;
+using HeuristicLab.Common;
+using HeuristicLab.MainForm.WindowsForms;
+using HeuristicLab.Visualization.ChartControlsExtensions;
+
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  public partial class PartialDependencePlot : UserControl, IPartialDependencePlot {
+    private ModifiableDataset sharedFixedVariables; // used for syncronising variable values between charts
+    private ModifiableDataset internalDataset; // holds the x values for each point drawn
+
+    private CancellationTokenSource cancelCurrentRecalculateSource;
+
+    private readonly List<IRegressionSolution> solutions;
+    private readonly Dictionary<IRegressionSolution, Series> seriesCache;
+    private readonly Dictionary<IRegressionSolution, Series> ciSeriesCache;
+
+    private readonly ToolStripMenuItem configToolStripMenuItem;
+    private readonly PartialDependencePlotConfigurationDialog configurationDialog;
+
+    #region Properties
+    public string XAxisTitle {
+      get { return chart.ChartAreas[0].AxisX.Title; }
+      set { chart.ChartAreas[0].AxisX.Title = value; }
+    }
+
+    public string YAxisTitle {
+      get { return chart.ChartAreas[0].AxisY.Title; }
+      set { chart.ChartAreas[0].AxisY.Title = value; }
+    }
+
+    public bool ShowLegend {
+      get { return chart.Legends[0].Enabled; }
+      set { chart.Legends[0].Enabled = value; }
+    }
+    public bool ShowCursor {
+      get { return chart.Annotations[0].Visible; }
+      set {
+        chart.Annotations[0].Visible = value;
+        if (!value) chart.Titles[0].Text = string.Empty;
+      }
+    }
+
+    public bool ShowConfigButton {
+      get { return configurationButton.Visible; }
+      set { configurationButton.Visible = value; }
+    }
+
+    private int xAxisTicks = 5;
+    public int XAxisTicks {
+      get { return xAxisTicks; }
+      set {
+        if (value != xAxisTicks) {
+          xAxisTicks = value;
+          SetupAxis(chart.ChartAreas[0].AxisX, trainingMin, trainingMax, XAxisTicks, FixedXAxisMin, FixedXAxisMax);
+          RecalculateInternalDataset();
+        }
+      }
+    }
+    private double? fixedXAxisMin;
+    public double? FixedXAxisMin {
+      get { return fixedXAxisMin; }
+      set {
+        if ((value.HasValue && fixedXAxisMin.HasValue && !value.Value.IsAlmost(fixedXAxisMin.Value)) || (value.HasValue != fixedXAxisMin.HasValue)) {
+          fixedXAxisMin = value;
+          if (trainingMin < trainingMax) {
+            SetupAxis(chart.ChartAreas[0].AxisX, trainingMin, trainingMax, XAxisTicks, FixedXAxisMin, FixedXAxisMax);
+            RecalculateInternalDataset();
+            // set the vertical line position 
+            if (VerticalLineAnnotation.X <= fixedXAxisMin) {
+              var axisX = chart.ChartAreas[0].AxisX;
+              var step = (axisX.Maximum - axisX.Minimum) / drawingSteps;
+              VerticalLineAnnotation.X = axisX.Minimum + step;
+            }
+          }
+        }
+      }
+    }
+    private double? fixedXAxisMax;
+    public double? FixedXAxisMax {
+      get { return fixedXAxisMax; }
+      set {
+        if ((value.HasValue && fixedXAxisMax.HasValue && !value.Value.IsAlmost(fixedXAxisMax.Value)) || (value.HasValue != fixedXAxisMax.HasValue)) {
+          fixedXAxisMax = value;
+          if (trainingMin < trainingMax) {
+            SetupAxis(chart.ChartAreas[0].AxisX, trainingMin, trainingMax, XAxisTicks, FixedXAxisMin, FixedXAxisMax);
+            RecalculateInternalDataset();
+            // set the vertical line position 
+            if (VerticalLineAnnotation.X >= fixedXAxisMax) {
+              var axisX = chart.ChartAreas[0].AxisX;
+              var step = (axisX.Maximum - axisX.Minimum) / drawingSteps;
+              VerticalLineAnnotation.X = axisX.Maximum - step;
+            }
+          }
+        }
+      }
+    }
+
+    private int yAxisTicks = 5;
+    public int YAxisTicks {
+      get { return yAxisTicks; }
+      set {
+        if (value != yAxisTicks) {
+          yAxisTicks = value;
+          SetupAxis(chart.ChartAreas[0].AxisY, yMin, yMax, YAxisTicks, FixedYAxisMin, FixedYAxisMax);
+          RecalculateInternalDataset();
+        }
+      }
+    }
+    private double? fixedYAxisMin;
+    public double? FixedYAxisMin {
+      get { return fixedYAxisMin; }
+      set {
+        if ((value.HasValue && fixedYAxisMin.HasValue && !value.Value.IsAlmost(fixedYAxisMin.Value)) || (value.HasValue != fixedYAxisMin.HasValue)) {
+          fixedYAxisMin = value;
+          SetupAxis(chart.ChartAreas[0].AxisY, yMin, yMax, YAxisTicks, FixedYAxisMin, FixedYAxisMax);
+        }
+      }
+    }
+    private double? fixedYAxisMax;
+    public double? FixedYAxisMax {
+      get { return fixedYAxisMax; }
+      set {
+        if ((value.HasValue && fixedYAxisMax.HasValue && !value.Value.IsAlmost(fixedYAxisMax.Value)) || (value.HasValue != fixedYAxisMax.HasValue)) {
+          fixedYAxisMax = value;
+          SetupAxis(chart.ChartAreas[0].AxisY, yMin, yMax, YAxisTicks, FixedYAxisMin, FixedYAxisMax);
+        }
+      }
+    }
+
+    private double trainingMin = 1;
+    private double trainingMax = -1;
+
+    private int drawingSteps = 1000;
+    public int DrawingSteps {
+      get { return drawingSteps; }
+      set {
+        if (value != drawingSteps) {
+          drawingSteps = value;
+          RecalculateInternalDataset();
+          ResizeAllSeriesData();
+        }
+      }
+    }
+
+    private string freeVariable;
+    public string FreeVariable {
+      get { return freeVariable; }
+      set {
+        if (value == freeVariable) return;
+        if (solutions.Any(s => !s.ProblemData.Dataset.DoubleVariables.Contains(value))) {
+          throw new ArgumentException("Variable does not exist in the ProblemData of the Solutions.");
+        }
+        freeVariable = value;
+        RecalculateInternalDataset();
+      }
+    }
+
+    private double yMin;
+    public double YMin {
+      get { return yMin; }
+    }
+    private double yMax;
+    public double YMax {
+      get { return yMax; }
+    }
+
+    public bool IsZoomed {
+      get { return chart.ChartAreas[0].AxisX.ScaleView.IsZoomed; }
+    }
+
+    private VerticalLineAnnotation VerticalLineAnnotation {
+      get { return (VerticalLineAnnotation)chart.Annotations.SingleOrDefault(x => x is VerticalLineAnnotation); }
+    }
+
+    internal ElementPosition InnerPlotPosition {
+      get { return chart.ChartAreas[0].InnerPlotPosition; }
+    }
+    #endregion
+
+    public event EventHandler ChartPostPaint;
+
+    public PartialDependencePlot() {
+      InitializeComponent();
+
+      solutions = new List<IRegressionSolution>();
+      seriesCache = new Dictionary<IRegressionSolution, Series>();
+      ciSeriesCache = new Dictionary<IRegressionSolution, Series>();
+
+      // Configure axis
+      chart.CustomizeAllChartAreas();
+      chart.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
+      chart.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
+      chart.ChartAreas[0].CursorX.Interval = 0;
+
+      chart.ChartAreas[0].CursorY.IsUserSelectionEnabled = true;
+      chart.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
+      chart.ChartAreas[0].CursorY.Interval = 0;
+
+      configToolStripMenuItem = new ToolStripMenuItem("Configuration");
+      configToolStripMenuItem.Click += config_Click;
+      chart.ContextMenuStrip.Items.Add(new ToolStripSeparator());
+      chart.ContextMenuStrip.Items.Add(configToolStripMenuItem);
+      configurationDialog = new PartialDependencePlotConfigurationDialog(this);
+
+      Disposed += Control_Disposed;
+    }
+
+    private void Control_Disposed(object sender, EventArgs e) {
+      if (cancelCurrentRecalculateSource != null)
+        cancelCurrentRecalculateSource.Cancel();
+    }
+
+    public void Configure(IEnumerable<IRegressionSolution> solutions, ModifiableDataset sharedFixedVariables, string freeVariable, int drawingSteps, bool initializeAxisRanges = true) {
+      if (!SolutionsCompatible(solutions))
+        throw new ArgumentException("Solutions are not compatible with the problem data.");
+      this.freeVariable = freeVariable;
+      this.drawingSteps = drawingSteps;
+
+      this.solutions.Clear();
+      this.solutions.AddRange(solutions);
+
+      // add an event such that whenever a value is changed in the shared dataset, 
+      // this change is reflected in the internal dataset (where the value becomes a whole column)
+      if (this.sharedFixedVariables != null)
+        this.sharedFixedVariables.ItemChanged -= sharedFixedVariables_ItemChanged;
+      this.sharedFixedVariables = sharedFixedVariables;
+      this.sharedFixedVariables.ItemChanged += sharedFixedVariables_ItemChanged;
+
+      RecalculateTrainingLimits(initializeAxisRanges);
+      RecalculateInternalDataset();
+
+      chart.Series.Clear();
+      seriesCache.Clear();
+      ciSeriesCache.Clear();
+      foreach (var solution in this.solutions) {
+        var series = CreateSeries(solution);
+        seriesCache.Add(solution, series.Item1);
+        if (series.Item2 != null)
+          ciSeriesCache.Add(solution, series.Item2);
+      }
+
+      // Set cursor and x-axis
+      // Make sure to allow a small offset to be able to distinguish the vertical line annotation from the axis
+      var defaultValue = sharedFixedVariables.GetDoubleValue(freeVariable, 0);
+      var step = (trainingMax - trainingMin) / drawingSteps;
+      var minimum = chart.ChartAreas[0].AxisX.Minimum;
+      var maximum = chart.ChartAreas[0].AxisX.Maximum;
+      if (defaultValue <= minimum)
+        VerticalLineAnnotation.X = minimum + step;
+      else if (defaultValue >= maximum)
+        VerticalLineAnnotation.X = maximum - step;
+      else
+        VerticalLineAnnotation.X = defaultValue;
+
+      if (ShowCursor)
+        chart.Titles[0].Text = FreeVariable + " : " + defaultValue.ToString("G5", CultureInfo.CurrentCulture);
+
+      ResizeAllSeriesData();
+      OrderAndColorSeries();
+    }
+
+    public async Task RecalculateAsync(bool updateOnFinish = true, bool resetYAxis = true) {
+      if (IsDisposed
+        || sharedFixedVariables == null || !solutions.Any() || string.IsNullOrEmpty(freeVariable)
+        || trainingMin.IsAlmost(trainingMax) || trainingMin > trainingMax || drawingSteps == 0)
+        return;
+
+      calculationPendingTimer.Start();
+
+      // cancel previous recalculate call
+      if (cancelCurrentRecalculateSource != null)
+        cancelCurrentRecalculateSource.Cancel();
+      cancelCurrentRecalculateSource = new CancellationTokenSource();
+      var cancellationToken = cancelCurrentRecalculateSource.Token;
+
+      // Update series
+      try {
+        var limits = await UpdateAllSeriesDataAsync(cancellationToken);
+
+        yMin = limits.Lower;
+        yMax = limits.Upper;
+        // Set y-axis
+        if (resetYAxis)
+          SetupAxis(chart.ChartAreas[0].AxisY, yMin, yMax, YAxisTicks, FixedYAxisMin, FixedYAxisMax);
+
+        UpdateOutOfTrainingRangeStripLines();
+
+        calculationPendingTimer.Stop();
+        calculationPendingLabel.Visible = false;
+        if (updateOnFinish)
+          Update();
+      } catch (OperationCanceledException) { } catch (AggregateException ae) {
+        if (!ae.InnerExceptions.Any(e => e is OperationCanceledException))
+          throw;
+      }
+    }
+
+    public void UpdateTitlePosition() {
+      var title = chart.Titles[0];
+      var plotArea = InnerPlotPosition;
+
+      title.Visible = plotArea.Width != 0;
+
+      title.Position.X = plotArea.X + (plotArea.Width / 2);
+    }
+
+    private void SetupAxis(Axis axis, double minValue, double maxValue, int ticks, double? fixedAxisMin, double? fixedAxisMax) {
+      if (minValue < maxValue) {
+        double axisMin, axisMax, axisInterval;
+        ChartUtil.CalculateAxisInterval(minValue, maxValue, ticks, out axisMin, out axisMax, out axisInterval);
+        axis.Minimum = fixedAxisMin ?? axisMin;
+        axis.Maximum = fixedAxisMax ?? axisMax;
+        axis.Interval = (axis.Maximum - axis.Minimum) / ticks;
+      }
+
+      try {
+        chart.ChartAreas[0].RecalculateAxesScale();
+      } catch (InvalidOperationException) {
+        // Can occur if eg. axis min == axis max
+      }
+    }
+
+    private void RecalculateTrainingLimits(bool initializeAxisRanges) {
+      trainingMin = solutions.Select(s => s.ProblemData.Dataset.GetDoubleValues(freeVariable, s.ProblemData.TrainingIndices).Min()).Max();
+      trainingMax = solutions.Select(s => s.ProblemData.Dataset.GetDoubleValues(freeVariable, s.ProblemData.TrainingIndices).Max()).Min();
+
+      if (initializeAxisRanges) {
+        double xmin, xmax, xinterval;
+        ChartUtil.CalculateAxisInterval(trainingMin, trainingMax, XAxisTicks, out xmin, out xmax, out xinterval);
+        FixedXAxisMin = xmin;
+        FixedXAxisMax = xmax;
+      }
+    }
+
+    private void RecalculateInternalDataset() {
+      if (sharedFixedVariables == null)
+        return;
+
+      // we expand the range in order to get nice tick intervals on the x axis
+      double xmin, xmax, xinterval;
+      ChartUtil.CalculateAxisInterval(trainingMin, trainingMax, XAxisTicks, out xmin, out xmax, out xinterval);
+
+      if (FixedXAxisMin.HasValue) xmin = FixedXAxisMin.Value;
+      if (FixedXAxisMax.HasValue) xmax = FixedXAxisMax.Value;
+      double step = (xmax - xmin) / drawingSteps;
+
+      var xvalues = new List<double>();
+      for (int i = 0; i < drawingSteps; i++)
+        xvalues.Add(xmin + i * step);
+
+      if (sharedFixedVariables == null)
+        return;
+
+      var variables = sharedFixedVariables.VariableNames.ToList();
+      var values = new List<IList>();
+      foreach (var varName in variables) {
+        if (varName == FreeVariable) {
+          values.Add(xvalues);
+        } else if (sharedFixedVariables.VariableHasType<double>(varName)) {
+          values.Add(Enumerable.Repeat(sharedFixedVariables.GetDoubleValue(varName, 0), xvalues.Count).ToList());
+        } else if (sharedFixedVariables.VariableHasType<string>(varName)) {
+          values.Add(Enumerable.Repeat(sharedFixedVariables.GetStringValue(varName, 0), xvalues.Count).ToList());
+        }
+      }
+
+      internalDataset = new ModifiableDataset(variables, values);
+    }
+
+    private Tuple<Series, Series> CreateSeries(IRegressionSolution solution) {
+      var series = new Series {
+        ChartType = SeriesChartType.Line,
+        Name = solution.ProblemData.TargetVariable + " " + solutions.IndexOf(solution)
+      };
+      series.LegendText = series.Name;
+
+      var confidenceBoundSolution = solution as IConfidenceRegressionSolution;
+      Series confidenceIntervalSeries = null;
+      if (confidenceBoundSolution != null) {
+        confidenceIntervalSeries = new Series {
+          ChartType = SeriesChartType.Range,
+          YValuesPerPoint = 2,
+          Name = "95% Conf. Interval " + series.Name,
+          IsVisibleInLegend = false
+        };
+      }
+      return Tuple.Create(series, confidenceIntervalSeries);
+    }
+
+    private void OrderAndColorSeries() {
+      chart.SuspendRepaint();
+
+      chart.Series.Clear();
+      // Add mean series for applying palette colors
+      foreach (var solution in solutions) {
+        chart.Series.Add(seriesCache[solution]);
+      }
+
+      chart.Palette = ChartColorPalette.BrightPastel;
+      chart.ApplyPaletteColors();
+      chart.Palette = ChartColorPalette.None;
+
+      // Add confidence interval series before its coresponding series for correct z index
+      foreach (var solution in solutions) {
+        Series ciSeries;
+        if (ciSeriesCache.TryGetValue(solution, out ciSeries)) {
+          var series = seriesCache[solution];
+          ciSeries.Color = Color.FromArgb(40, series.Color);
+          int idx = chart.Series.IndexOf(seriesCache[solution]);
+          chart.Series.Insert(idx, ciSeries);
+        }
+      }
+
+      chart.ResumeRepaint(true);
+    }
+
+    private async Task<DoubleLimit> UpdateAllSeriesDataAsync(CancellationToken cancellationToken) {
+      var updateTasks = solutions.Select(solution => UpdateSeriesDataAsync(solution, cancellationToken));
+
+      double min = double.MaxValue, max = double.MinValue;
+      foreach (var update in updateTasks) {
+        var limit = await update;
+        if (limit.Lower < min) min = limit.Lower;
+        if (limit.Upper > max) max = limit.Upper;
+      }
+
+      return new DoubleLimit(min, max);
+    }
+
+    private Task<DoubleLimit> UpdateSeriesDataAsync(IRegressionSolution solution, CancellationToken cancellationToken) {
+      return Task.Run(() => {
+        var xvalues = internalDataset.GetDoubleValues(FreeVariable).ToList();
+        var yvalues = solution.Model.GetEstimatedValues(internalDataset, Enumerable.Range(0, internalDataset.Rows)).ToList();
+
+        double min = double.MaxValue, max = double.MinValue;
+
+        var series = seriesCache[solution];
+        for (int i = 0; i < xvalues.Count; i++) {
+          series.Points[i].SetValueXY(xvalues[i], yvalues[i]);
+          if (yvalues[i] < min) min = yvalues[i];
+          if (yvalues[i] > max) max = yvalues[i];
+        }
+        chart.Invalidate();
+
+        cancellationToken.ThrowIfCancellationRequested();
+
+        var confidenceBoundSolution = solution as IConfidenceRegressionSolution;
+        if (confidenceBoundSolution != null) {
+          var confidenceIntervalSeries = ciSeriesCache[solution];
+          var variances = confidenceBoundSolution.Model.GetEstimatedVariances(internalDataset, Enumerable.Range(0, internalDataset.Rows)).ToList();
+          for (int i = 0; i < xvalues.Count; i++) {
+            var lower = yvalues[i] - 1.96 * Math.Sqrt(variances[i]);
+            var upper = yvalues[i] + 1.96 * Math.Sqrt(variances[i]);
+            confidenceIntervalSeries.Points[i].SetValueXY(xvalues[i], lower, upper);
+            if (lower < min) min = lower;
+            if (upper > max) max = upper;
+          }
+          chart.Invalidate();
+        }
+
+        cancellationToken.ThrowIfCancellationRequested();
+        return new DoubleLimit(min, max);
+      }, cancellationToken);
+    }
+
+    private void ResizeAllSeriesData() {
+      if (internalDataset == null)
+        return;
+
+      var xvalues = internalDataset.GetDoubleValues(FreeVariable).ToList();
+      foreach (var solution in solutions)
+        ResizeSeriesData(solution, xvalues);
+    }
+    private void ResizeSeriesData(IRegressionSolution solution, IList<double> xvalues = null) {
+      if (xvalues == null)
+        xvalues = internalDataset.GetDoubleValues(FreeVariable).ToList();
+
+      var series = seriesCache[solution];
+      series.Points.SuspendUpdates();
+      series.Points.Clear();
+      for (int i = 0; i < xvalues.Count; i++)
+        series.Points.Add(new DataPoint(xvalues[i], 0.0));
+      series.Points.ResumeUpdates();
+
+      Series confidenceIntervalSeries;
+      if (ciSeriesCache.TryGetValue(solution, out confidenceIntervalSeries)) {
+        confidenceIntervalSeries.Points.SuspendUpdates();
+        confidenceIntervalSeries.Points.Clear();
+        for (int i = 0; i < xvalues.Count; i++)
+          confidenceIntervalSeries.Points.Add(new DataPoint(xvalues[i], new[] { -1.0, 1.0 }));
+        confidenceIntervalSeries.Points.ResumeUpdates();
+      }
+    }
+
+    public async Task AddSolutionAsync(IRegressionSolution solution) {
+      if (!SolutionsCompatible(solutions.Concat(new[] { solution })))
+        throw new ArgumentException("The solution is not compatible with the problem data.");
+      if (solutions.Contains(solution))
+        return;
+
+      solutions.Add(solution);
+      RecalculateTrainingLimits(true);
+
+      var series = CreateSeries(solution);
+      seriesCache.Add(solution, series.Item1);
+      if (series.Item2 != null)
+        ciSeriesCache.Add(solution, series.Item2);
+
+      ResizeSeriesData(solution);
+      OrderAndColorSeries();
+
+      await RecalculateAsync();
+      var args = new EventArgs<IRegressionSolution>(solution);
+      OnSolutionAdded(this, args);
+    }
+
+    public async Task RemoveSolutionAsync(IRegressionSolution solution) {
+      if (!solutions.Remove(solution))
+        return;
+
+      RecalculateTrainingLimits(true);
+
+      seriesCache.Remove(solution);
+      ciSeriesCache.Remove(solution);
+
+      await RecalculateAsync();
+      var args = new EventArgs<IRegressionSolution>(solution);
+      OnSolutionRemoved(this, args);
+    }
+
+    private static bool SolutionsCompatible(IEnumerable<IRegressionSolution> solutions) {
+      var refSolution = solutions.First();
+      var refSolVars = refSolution.ProblemData.Dataset.VariableNames;
+      foreach (var solution in solutions.Skip(1)) {
+        var variables1 = solution.ProblemData.Dataset.VariableNames;
+        if (!variables1.All(refSolVars.Contains))
+          return false;
+
+        foreach (var factorVar in variables1.Where(solution.ProblemData.Dataset.VariableHasType<string>)) {
+          var distinctVals = refSolution.ProblemData.Dataset.GetStringValues(factorVar).Distinct();
+          if (solution.ProblemData.Dataset.GetStringValues(factorVar).Any(val => !distinctVals.Contains(val))) return false;
+        }
+      }
+      return true;
+    }
+
+    private void UpdateOutOfTrainingRangeStripLines() {
+      var axisX = chart.ChartAreas[0].AxisX;
+      var lowerStripLine = axisX.StripLines[0];
+      var upperStripLine = axisX.StripLines[1];
+
+      lowerStripLine.IntervalOffset = axisX.Minimum;
+      lowerStripLine.StripWidth = Math.Abs(trainingMin - axisX.Minimum);
+
+      upperStripLine.IntervalOffset = trainingMax;
+      upperStripLine.StripWidth = Math.Abs(axisX.Maximum - trainingMax);
+    }
+
+    #region Events
+    public event EventHandler<EventArgs<IRegressionSolution>> SolutionAdded;
+    public void OnSolutionAdded(object sender, EventArgs<IRegressionSolution> args) {
+      var added = SolutionAdded;
+      if (added == null) return;
+      added(sender, args);
+    }
+
+    public event EventHandler<EventArgs<IRegressionSolution>> SolutionRemoved;
+    public void OnSolutionRemoved(object sender, EventArgs<IRegressionSolution> args) {
+      var removed = SolutionRemoved;
+      if (removed == null) return;
+      removed(sender, args);
+    }
+
+    public event EventHandler VariableValueChanged;
+    public void OnVariableValueChanged(object sender, EventArgs args) {
+      var changed = VariableValueChanged;
+      if (changed == null) return;
+      changed(sender, args);
+    }
+
+    public event EventHandler ZoomChanged;
+    public void OnZoomChanged(object sender, EventArgs args) {
+      var changed = ZoomChanged;
+      if (changed == null) return;
+      changed(sender, args);
+    }
+
+    private void sharedFixedVariables_ItemChanged(object o, EventArgs<int, int> e) {
+      if (o != sharedFixedVariables) return;
+      var variables = sharedFixedVariables.VariableNames.ToList();
+      var rowIndex = e.Value;
+      var columnIndex = e.Value2;
+
+      var variableName = variables[columnIndex];
+      if (variableName == FreeVariable) return;
+      if (internalDataset.VariableHasType<double>(variableName)) {
+        var v = sharedFixedVariables.GetDoubleValue(variableName, rowIndex);
+        var values = new List<double>(Enumerable.Repeat(v, internalDataset.Rows));
+        internalDataset.ReplaceVariable(variableName, values);
+      } else if (internalDataset.VariableHasType<string>(variableName)) {
+        var v = sharedFixedVariables.GetStringValue(variableName, rowIndex);
+        var values = new List<String>(Enumerable.Repeat(v, internalDataset.Rows));
+        internalDataset.ReplaceVariable(variableName, values);
+      } else {
+        // unsupported type 
+        throw new NotSupportedException();
+      }
+    }
+
+    private void chart_AnnotationPositionChanging(object sender, AnnotationPositionChangingEventArgs e) {
+      var step = (trainingMax - trainingMin) / drawingSteps;
+      double newLocation = step * (long)Math.Round(e.NewLocationX / step);
+      var axisX = chart.ChartAreas[0].AxisX;
+      if (newLocation >= axisX.Maximum)
+        newLocation = axisX.Maximum - step;
+      if (newLocation <= axisX.Minimum)
+        newLocation = axisX.Minimum + step;
+
+      e.NewLocationX = newLocation;
+
+      UpdateCursor();
+    }
+    private void chart_AnnotationPositionChanged(object sender, EventArgs e) {
+      UpdateCursor();
+    }
+    private void UpdateCursor() {
+      var x = VerticalLineAnnotation.X;
+      sharedFixedVariables.SetVariableValue(x, FreeVariable, 0);
+
+      if (ShowCursor) {
+        chart.Titles[0].Text = FreeVariable + " : " + x.ToString("G5", CultureInfo.CurrentCulture);
+        chart.Update();
+      }
+
+      OnVariableValueChanged(this, EventArgs.Empty);
+    }
+
+    private void chart_MouseMove(object sender, MouseEventArgs e) {
+      bool hitCursor = chart.HitTest(e.X, e.Y).ChartElementType == ChartElementType.Annotation;
+      chart.Cursor = hitCursor ? Cursors.VSplit : Cursors.Default;
+    }
+
+    private async void chart_DragDrop(object sender, DragEventArgs e) {
+      var data = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
+      if (data != null) {
+        var solution = data as IRegressionSolution;
+        if (!solutions.Contains(solution))
+          await AddSolutionAsync(solution);
+      }
+    }
+    private void chart_DragEnter(object sender, DragEventArgs e) {
+      if (!e.Data.GetDataPresent(HeuristicLab.Common.Constants.DragDropDataFormat)) return;
+      e.Effect = DragDropEffects.None;
+
+      var data = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
+      var regressionSolution = data as IRegressionSolution;
+      if (regressionSolution != null) {
+        e.Effect = DragDropEffects.Copy;
+      }
+    }
+
+    private void calculationPendingTimer_Tick(object sender, EventArgs e) {
+      calculationPendingLabel.Visible = true;
+      Update();
+    }
+
+    private void config_Click(object sender, EventArgs e) {
+      configurationDialog.ShowDialog(this);
+    }
+
+    private void chart_SelectionRangeChanged(object sender, CursorEventArgs e) {
+      OnZoomChanged(this, EventArgs.Empty);
+    }
+
+    private void chart_Resize(object sender, EventArgs e) {
+      UpdateTitlePosition();
+    }
+
+    private void chart_PostPaint(object sender, ChartPaintEventArgs e) {
+      if (ChartPostPaint != null)
+        ChartPostPaint(this, EventArgs.Empty);
+    }
+    #endregion
+  }
+}
+
Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/PartialDependencePlotConfigurationDialog.Designer.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/PartialDependencePlotConfigurationDialog.Designer.cs	(revision 15137)
+++ stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/PartialDependencePlotConfigurationDialog.Designer.cs	(revision 15137)
@@ -0,0 +1,327 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  partial class PartialDependencePlotConfigurationDialog {
+    /// <summary>
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary>
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Windows Form Designer generated code
+
+    /// <summary>
+    /// Required method for Designer support - do not modify
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      this.components = new System.ComponentModel.Container();
+      this.xAxisGroupBox = new System.Windows.Forms.GroupBox();
+      this.maxXTextBox = new System.Windows.Forms.TextBox();
+      this.xAutomaticCheckBox = new System.Windows.Forms.CheckBox();
+      this.minXTextBox = new System.Windows.Forms.TextBox();
+      this.maxXLabel = new System.Windows.Forms.Label();
+      this.minXLabel = new System.Windows.Forms.Label();
+      this.yAxisGroupBox = new System.Windows.Forms.GroupBox();
+      this.maxYTextBox = new System.Windows.Forms.TextBox();
+      this.yAutomaticCheckBox = new System.Windows.Forms.CheckBox();
+      this.minYTextBox = new System.Windows.Forms.TextBox();
+      this.maxYLabel = new System.Windows.Forms.Label();
+      this.minYLabel = new System.Windows.Forms.Label();
+      this.miscGroupBox = new System.Windows.Forms.GroupBox();
+      this.StepsNumericUpDown = new System.Windows.Forms.NumericUpDown();
+      this.stepsLabel = new System.Windows.Forms.Label();
+      this.applyButton = new System.Windows.Forms.Button();
+      this.cancelButton = new System.Windows.Forms.Button();
+      this.errorProvider = new System.Windows.Forms.ErrorProvider(this.components);
+      this.xAxisGroupBox.SuspendLayout();
+      this.yAxisGroupBox.SuspendLayout();
+      this.miscGroupBox.SuspendLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.StepsNumericUpDown)).BeginInit();
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // xAxisGroupBox
+      // 
+      this.xAxisGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.xAxisGroupBox.Controls.Add(this.maxXTextBox);
+      this.xAxisGroupBox.Controls.Add(this.xAutomaticCheckBox);
+      this.xAxisGroupBox.Controls.Add(this.minXTextBox);
+      this.xAxisGroupBox.Controls.Add(this.maxXLabel);
+      this.xAxisGroupBox.Controls.Add(this.minXLabel);
+      this.xAxisGroupBox.Location = new System.Drawing.Point(12, 12);
+      this.xAxisGroupBox.Name = "xAxisGroupBox";
+      this.xAxisGroupBox.Size = new System.Drawing.Size(234, 78);
+      this.xAxisGroupBox.TabIndex = 1;
+      this.xAxisGroupBox.TabStop = false;
+      this.xAxisGroupBox.Text = "X-Axis";
+      // 
+      // maxXTextBox
+      // 
+      this.maxXTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.maxXTextBox.Location = new System.Drawing.Point(61, 45);
+      this.maxXTextBox.Name = "maxXTextBox";
+      this.maxXTextBox.Size = new System.Drawing.Size(167, 20);
+      this.maxXTextBox.TabIndex = 3;
+      this.maxXTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.numberTextBox_Validating);
+      this.maxXTextBox.Validated += new System.EventHandler(this.numberTextBox_Validated);
+      // 
+      // xAutomaticCheckBox
+      // 
+      this.xAutomaticCheckBox.AutoSize = true;
+      this.xAutomaticCheckBox.Location = new System.Drawing.Point(48, -1);
+      this.xAutomaticCheckBox.Name = "xAutomaticCheckBox";
+      this.xAutomaticCheckBox.Size = new System.Drawing.Size(73, 17);
+      this.xAutomaticCheckBox.TabIndex = 1;
+      this.xAutomaticCheckBox.Text = "Automatic";
+      this.xAutomaticCheckBox.UseVisualStyleBackColor = true;
+      this.xAutomaticCheckBox.CheckedChanged += new System.EventHandler(this.automaticCheckBox_CheckedChanged);
+      // 
+      // minXTextBox
+      // 
+      this.minXTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.minXTextBox.Location = new System.Drawing.Point(61, 19);
+      this.minXTextBox.Name = "minXTextBox";
+      this.minXTextBox.Size = new System.Drawing.Size(167, 20);
+      this.minXTextBox.TabIndex = 2;
+      this.minXTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.numberTextBox_Validating);
+      this.minXTextBox.Validated += new System.EventHandler(this.numberTextBox_Validated);
+      // 
+      // maxXLabel
+      // 
+      this.maxXLabel.AutoSize = true;
+      this.maxXLabel.Location = new System.Drawing.Point(7, 48);
+      this.maxXLabel.Name = "maxXLabel";
+      this.maxXLabel.Size = new System.Drawing.Size(27, 13);
+      this.maxXLabel.TabIndex = 1;
+      this.maxXLabel.Text = "Max";
+      // 
+      // minXLabel
+      // 
+      this.minXLabel.AutoSize = true;
+      this.minXLabel.Location = new System.Drawing.Point(7, 22);
+      this.minXLabel.Name = "minXLabel";
+      this.minXLabel.Size = new System.Drawing.Size(24, 13);
+      this.minXLabel.TabIndex = 0;
+      this.minXLabel.Text = "Min";
+      // 
+      // yAxisGroupBox
+      // 
+      this.yAxisGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.yAxisGroupBox.Controls.Add(this.maxYTextBox);
+      this.yAxisGroupBox.Controls.Add(this.yAutomaticCheckBox);
+      this.yAxisGroupBox.Controls.Add(this.minYTextBox);
+      this.yAxisGroupBox.Controls.Add(this.maxYLabel);
+      this.yAxisGroupBox.Controls.Add(this.minYLabel);
+      this.yAxisGroupBox.Location = new System.Drawing.Point(13, 96);
+      this.yAxisGroupBox.Name = "yAxisGroupBox";
+      this.yAxisGroupBox.Size = new System.Drawing.Size(234, 75);
+      this.yAxisGroupBox.TabIndex = 2;
+      this.yAxisGroupBox.TabStop = false;
+      this.yAxisGroupBox.Text = "Y-Axis";
+      // 
+      // maxYTextBox
+      // 
+      this.maxYTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.maxYTextBox.Location = new System.Drawing.Point(61, 45);
+      this.maxYTextBox.Name = "maxYTextBox";
+      this.maxYTextBox.Size = new System.Drawing.Size(167, 20);
+      this.maxYTextBox.TabIndex = 3;
+      this.maxYTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.numberTextBox_Validating);
+      this.maxYTextBox.Validated += new System.EventHandler(this.numberTextBox_Validated);
+      // 
+      // yAutomaticCheckBox
+      // 
+      this.yAutomaticCheckBox.AutoSize = true;
+      this.yAutomaticCheckBox.Location = new System.Drawing.Point(47, -1);
+      this.yAutomaticCheckBox.Name = "yAutomaticCheckBox";
+      this.yAutomaticCheckBox.Size = new System.Drawing.Size(73, 17);
+      this.yAutomaticCheckBox.TabIndex = 1;
+      this.yAutomaticCheckBox.Text = "Automatic";
+      this.yAutomaticCheckBox.UseVisualStyleBackColor = true;
+      this.yAutomaticCheckBox.CheckedChanged += new System.EventHandler(this.automaticCheckBox_CheckedChanged);
+      // 
+      // minYTextBox
+      // 
+      this.minYTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.minYTextBox.Location = new System.Drawing.Point(61, 19);
+      this.minYTextBox.Name = "minYTextBox";
+      this.minYTextBox.Size = new System.Drawing.Size(167, 20);
+      this.minYTextBox.TabIndex = 2;
+      this.minYTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.numberTextBox_Validating);
+      this.minYTextBox.Validated += new System.EventHandler(this.numberTextBox_Validated);
+      // 
+      // maxYLabel
+      // 
+      this.maxYLabel.AutoSize = true;
+      this.maxYLabel.Location = new System.Drawing.Point(7, 48);
+      this.maxYLabel.Name = "maxYLabel";
+      this.maxYLabel.Size = new System.Drawing.Size(27, 13);
+      this.maxYLabel.TabIndex = 1;
+      this.maxYLabel.Text = "Max";
+      // 
+      // minYLabel
+      // 
+      this.minYLabel.AutoSize = true;
+      this.minYLabel.Location = new System.Drawing.Point(7, 22);
+      this.minYLabel.Name = "minYLabel";
+      this.minYLabel.Size = new System.Drawing.Size(24, 13);
+      this.minYLabel.TabIndex = 0;
+      this.minYLabel.Text = "Min";
+      // 
+      // miscGroupBox
+      // 
+      this.miscGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.miscGroupBox.Controls.Add(this.StepsNumericUpDown);
+      this.miscGroupBox.Controls.Add(this.stepsLabel);
+      this.miscGroupBox.Location = new System.Drawing.Point(13, 177);
+      this.miscGroupBox.Name = "miscGroupBox";
+      this.miscGroupBox.Size = new System.Drawing.Size(233, 53);
+      this.miscGroupBox.TabIndex = 4;
+      this.miscGroupBox.TabStop = false;
+      // 
+      // StepsNumericUpDown
+      // 
+      this.StepsNumericUpDown.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.StepsNumericUpDown.Increment = new decimal(new int[] {
+            50,
+            0,
+            0,
+            0});
+      this.StepsNumericUpDown.Location = new System.Drawing.Point(61, 20);
+      this.StepsNumericUpDown.Maximum = new decimal(new int[] {
+            100000,
+            0,
+            0,
+            0});
+      this.StepsNumericUpDown.Name = "StepsNumericUpDown";
+      this.StepsNumericUpDown.Size = new System.Drawing.Size(166, 20);
+      this.StepsNumericUpDown.TabIndex = 4;
+      // 
+      // stepsLabel
+      // 
+      this.stepsLabel.AutoSize = true;
+      this.stepsLabel.Location = new System.Drawing.Point(6, 22);
+      this.stepsLabel.Name = "stepsLabel";
+      this.stepsLabel.Size = new System.Drawing.Size(34, 13);
+      this.stepsLabel.TabIndex = 1;
+      this.stepsLabel.Text = "Steps";
+      // 
+      // applyButton
+      // 
+      this.applyButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+      this.applyButton.Location = new System.Drawing.Point(91, 239);
+      this.applyButton.Name = "applyButton";
+      this.applyButton.Size = new System.Drawing.Size(75, 23);
+      this.applyButton.TabIndex = 5;
+      this.applyButton.Text = "Apply";
+      this.applyButton.UseVisualStyleBackColor = true;
+      this.applyButton.Click += new System.EventHandler(this.okButton_Click);
+      // 
+      // cancelButton
+      // 
+      this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+      this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+      this.cancelButton.Location = new System.Drawing.Point(172, 239);
+      this.cancelButton.Name = "cancelButton";
+      this.cancelButton.Size = new System.Drawing.Size(75, 23);
+      this.cancelButton.TabIndex = 6;
+      this.cancelButton.Text = "Cancel";
+      this.cancelButton.UseVisualStyleBackColor = true;
+      // 
+      // errorProvider
+      // 
+      this.errorProvider.BlinkStyle = System.Windows.Forms.ErrorBlinkStyle.NeverBlink;
+      this.errorProvider.ContainerControl = this;
+      // 
+      // PartialDependencePlotConfigurationDialog
+      // 
+      this.AcceptButton = this.applyButton;
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
+      this.CancelButton = this.cancelButton;
+      this.ClientSize = new System.Drawing.Size(258, 272);
+      this.Controls.Add(this.cancelButton);
+      this.Controls.Add(this.applyButton);
+      this.Controls.Add(this.miscGroupBox);
+      this.Controls.Add(this.xAxisGroupBox);
+      this.Controls.Add(this.yAxisGroupBox);
+      this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+      this.MaximizeBox = false;
+      this.MinimizeBox = false;
+      this.Name = "PartialDependencePlotConfigurationDialog";
+      this.ShowIcon = false;
+      this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
+      this.Text = "Configure Gradient Chart";
+      this.TopMost = true;
+      this.Shown += new System.EventHandler(this.PartialDependencePlotConfigurationDialog_Shown);
+      this.xAxisGroupBox.ResumeLayout(false);
+      this.xAxisGroupBox.PerformLayout();
+      this.yAxisGroupBox.ResumeLayout(false);
+      this.yAxisGroupBox.PerformLayout();
+      this.miscGroupBox.ResumeLayout(false);
+      this.miscGroupBox.PerformLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.StepsNumericUpDown)).EndInit();
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit();
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.GroupBox xAxisGroupBox;
+    private System.Windows.Forms.TextBox maxXTextBox;
+    private System.Windows.Forms.TextBox minXTextBox;
+    private System.Windows.Forms.Label maxXLabel;
+    private System.Windows.Forms.Label minXLabel;
+    private System.Windows.Forms.GroupBox yAxisGroupBox;
+    private System.Windows.Forms.TextBox maxYTextBox;
+    private System.Windows.Forms.CheckBox yAutomaticCheckBox;
+    private System.Windows.Forms.TextBox minYTextBox;
+    private System.Windows.Forms.Label maxYLabel;
+    private System.Windows.Forms.Label minYLabel;
+    private System.Windows.Forms.GroupBox miscGroupBox;
+    private System.Windows.Forms.Label stepsLabel;
+    private System.Windows.Forms.Button applyButton;
+    private System.Windows.Forms.Button cancelButton;
+    private System.Windows.Forms.CheckBox xAutomaticCheckBox;
+    private System.Windows.Forms.NumericUpDown StepsNumericUpDown;
+    private System.Windows.Forms.ErrorProvider errorProvider;
+  }
+}
Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/PartialDependencePlotConfigurationDialog.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/PartialDependencePlotConfigurationDialog.cs	(revision 15137)
+++ stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/PartialDependencePlotConfigurationDialog.cs	(revision 15137)
@@ -0,0 +1,121 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.ComponentModel;
+using System.Globalization;
+using System.Windows.Forms;
+using HeuristicLab.MainForm.WindowsForms;
+
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  public partial class PartialDependencePlotConfigurationDialog : Form {
+    private readonly PartialDependencePlot chart;
+
+    public PartialDependencePlotConfigurationDialog(PartialDependencePlot chart) {
+      this.chart = chart;
+      InitializeComponent();
+    }
+
+    private void PartialDependencePlotConfigurationDialog_Shown(object sender, EventArgs e) {
+      if (chart.FixedXAxisMin.HasValue && chart.FixedXAxisMax.HasValue) {
+        xAutomaticCheckBox.Checked = false;
+        minXTextBox.Text = chart.FixedXAxisMin.Value.ToString(CultureInfo.CurrentUICulture);
+        maxXTextBox.Text = chart.FixedXAxisMax.Value.ToString(CultureInfo.CurrentUICulture);
+      } else xAutomaticCheckBox.Checked = true;
+      if (chart.FixedYAxisMin.HasValue && chart.FixedYAxisMax.HasValue) {
+        yAutomaticCheckBox.Checked = false;
+        minYTextBox.Text = chart.FixedYAxisMin.Value.ToString(CultureInfo.CurrentUICulture);
+        maxYTextBox.Text = chart.FixedYAxisMax.Value.ToString(CultureInfo.CurrentUICulture);
+      } else yAutomaticCheckBox.Checked = true;
+      StepsNumericUpDown.Value = chart.DrawingSteps;
+    }
+
+    private async void okButton_Click(object sender, System.EventArgs e) {
+      try {
+        Enabled = false;
+        chart.SuspendRepaint();
+        if (xAutomaticCheckBox.Checked) {
+          chart.FixedXAxisMin = null;
+          chart.FixedXAxisMax = null;
+        } else {
+          var min = double.Parse(minXTextBox.Text, CultureInfo.CurrentUICulture);
+          var max = double.Parse(maxXTextBox.Text, CultureInfo.CurrentUICulture);
+          chart.FixedXAxisMin = min;
+          chart.FixedXAxisMax = max;
+        }
+
+        if (yAutomaticCheckBox.Checked) {
+          chart.FixedYAxisMin = null;
+          chart.FixedYAxisMax = null;
+        } else {
+          var min = double.Parse(minYTextBox.Text, CultureInfo.CurrentUICulture);
+          var max = double.Parse(maxYTextBox.Text, CultureInfo.CurrentUICulture);
+          chart.FixedYAxisMin = min;
+          chart.FixedYAxisMax = max;
+        }
+
+        chart.DrawingSteps = (int)StepsNumericUpDown.Value;
+
+        await chart.RecalculateAsync(resetYAxis: false);
+
+        Close();
+      }
+      catch (FormatException) {
+        MessageBox.Show(this, "Illegal number format", "Wrong format", MessageBoxButtons.OK, MessageBoxIcon.Error);
+      }
+      finally {
+        Enabled = true;
+        chart.ResumeRepaint(true);
+      }
+    }
+
+    private void automaticCheckBox_CheckedChanged(object sender, EventArgs e) {
+      minXTextBox.Enabled = !xAutomaticCheckBox.Checked;
+      maxXTextBox.Enabled = !xAutomaticCheckBox.Checked;
+
+      minYTextBox.Enabled = !yAutomaticCheckBox.Checked;
+      maxYTextBox.Enabled = !yAutomaticCheckBox.Checked;
+    }
+
+    private void numberTextBox_Validating(object sender, CancelEventArgs e) {
+      var textBox = sender as TextBox;
+      if (textBox != null) {
+        double number;
+        if (!double.TryParse(textBox.Text, NumberStyles.Any, CultureInfo.CurrentUICulture, out number)) {
+          e.Cancel = true;
+          applyButton.Enabled = false;
+          errorProvider.SetIconAlignment(textBox, ErrorIconAlignment.MiddleLeft);
+          errorProvider.SetIconPadding(textBox, 2);
+          errorProvider.SetError(textBox, "Illegal number format");
+          textBox.SelectAll();
+        }
+      }
+    }
+
+    private void numberTextBox_Validated(object sender, EventArgs e) {
+      var textBox = sender as TextBox;
+      if (textBox != null) {
+        errorProvider.SetError(textBox, string.Empty);
+        applyButton.Enabled = true;
+      }
+    }
+  }
+}
Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj	(revision 15131)
+++ stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj	(revision 15137)
@@ -132,9 +132,21 @@
       <DependentUpon>DensityTrackbar.cs</DependentUpon>
     </Compile>
-    <Compile Include="Controls\FactorGradientChart.cs">
-      <SubType>UserControl</SubType>
-    </Compile>
-    <Compile Include="Controls\FactorGradientChart.Designer.cs">
-      <DependentUpon>FactorGradientChart.cs</DependentUpon>
+    <Compile Include="Controls\FactorPartialDependencePlot.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Controls\FactorPartialDependencePlot.Designer.cs">
+      <DependentUpon>FactorPartialDependencePlot.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Controls\PartialDependencePlot.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Controls\PartialDependencePlot.Designer.cs">
+      <DependentUpon>PartialDependencePlot.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Controls\PartialDependencePlotConfigurationDialog.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Controls\PartialDependencePlotConfigurationDialog.Designer.cs">
+      <DependentUpon>PartialDependencePlotConfigurationDialog.cs</DependentUpon>
     </Compile>
     <Compile Include="FeatureCorrelation\TimeframeFeatureCorrelationCalculator.cs" />
@@ -201,18 +213,6 @@
       <DependentUpon>FeatureCorrelationView.cs</DependentUpon>
     </Compile>
-    <Compile Include="Controls\GradientChart.cs">
-      <SubType>UserControl</SubType>
-    </Compile>
-    <Compile Include="Controls\GradientChart.Designer.cs">
-      <DependentUpon>GradientChart.cs</DependentUpon>
-    </Compile>
-    <Compile Include="Controls\GradientChartConfigurationDialog.cs">
-      <SubType>Form</SubType>
-    </Compile>
-    <Compile Include="Controls\GradientChartConfigurationDialog.Designer.cs">
-      <DependentUpon>GradientChartConfigurationDialog.cs</DependentUpon>
-    </Compile>
-    <Compile Include="Interfaces\IGradientChart.cs" />
     <Compile Include="Interfaces\IDataPreprocessorStarter.cs" />
+    <Compile Include="Interfaces\IPartialDependencePlot.cs" />
     <Compile Include="MenuItems\ChangeDataOfOptimizersMenuItem.cs" />
     <Compile Include="MenuItems\ShrinkDataAnalysisRunsMenuItem.cs" />
@@ -260,4 +260,10 @@
       <DependentUpon>RegressionSolutionLineChartViewBase.cs</DependentUpon>
     </Compile>
+    <Compile Include="Regression\RegressionSolutionPartialDependencePlotView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Regression\RegressionSolutionPartialDependencePlotView.Designer.cs">
+      <DependentUpon>RegressionSolutionPartialDependencePlotView.cs</DependentUpon>
+    </Compile>
     <Compile Include="Regression\RegressionSolutionResidualsLineChartView.cs">
       <SubType>UserControl</SubType>
@@ -277,10 +283,4 @@
     <Compile Include="Regression\RegressionSolutionGradientView.Designer.cs">
       <DependentUpon>RegressionSolutionGradientView.cs</DependentUpon>
-    </Compile>
-    <Compile Include="Regression\RegressionSolutionTargetResponseGradientView.cs">
-      <SubType>UserControl</SubType>
-    </Compile>
-    <Compile Include="Regression\RegressionSolutionTargetResponseGradientView.Designer.cs">
-      <DependentUpon>RegressionSolutionTargetResponseGradientView.cs</DependentUpon>
     </Compile>
     <Compile Include="Regression\RegressionTimeframeFeatureCorrelationView.cs">
Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Interfaces/IGradientChart.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Interfaces/IGradientChart.cs	(revision 15131)
+++ 	(revision )
@@ -1,37 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System.Threading.Tasks;
-
-namespace HeuristicLab.Problems.DataAnalysis.Views {
-  public interface IGradientChart {
-    Task RecalculateAsync(bool updateOnFinish, bool resetYAxis);
-    double YMin { get;  }
-    double YMax { get; }
-    double? FixedYAxisMin { get; set; }
-    double? FixedYAxisMax { get; set; }
-    string YAxisTitle { get; set; }
-    Task AddSolutionAsync(IRegressionSolution solution);
-    Task RemoveSolutionAsync(IRegressionSolution solution);
-    bool IsZoomed { get; }
-    void Refresh();
-  }
-}
Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Interfaces/IPartialDependencePlot.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Interfaces/IPartialDependencePlot.cs	(revision 15137)
+++ stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Interfaces/IPartialDependencePlot.cs	(revision 15137)
@@ -0,0 +1,37 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Threading.Tasks;
+
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  public interface IPartialDependencePlot {
+    Task RecalculateAsync(bool updateOnFinish, bool resetYAxis);
+    double YMin { get;  }
+    double YMax { get; }
+    double? FixedYAxisMin { get; set; }
+    double? FixedYAxisMax { get; set; }
+    string YAxisTitle { get; set; }
+    Task AddSolutionAsync(IRegressionSolution solution);
+    Task RemoveSolutionAsync(IRegressionSolution solution);
+    bool IsZoomed { get; }
+    void Refresh();
+  }
+}
Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionGradientView.Designer.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionGradientView.Designer.cs	(revision 15131)
+++ stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionGradientView.Designer.cs	(revision 15137)
@@ -46,5 +46,5 @@
     private void InitializeComponent() {
       this.splitContainer = new System.Windows.Forms.SplitContainer();
-      this.gradientChart = new HeuristicLab.Problems.DataAnalysis.Views.GradientChart();
+      this._partialDependencePlot = new HeuristicLab.Problems.DataAnalysis.Views.PartialDependencePlot();
       this.configurationGroupBox = new System.Windows.Forms.GroupBox();
       this.tableLayoutPanel = new System.Windows.Forms.TableLayoutPanel();
@@ -65,5 +65,5 @@
       // splitContainer.Panel1
       // 
-      this.splitContainer.Panel1.Controls.Add(this.gradientChart);
+      this.splitContainer.Panel1.Controls.Add(this._partialDependencePlot);
       // 
       // splitContainer.Panel2
@@ -74,16 +74,16 @@
       this.splitContainer.TabIndex = 1;
       // 
-      // gradientChart
+      // _partialDependencePlot
       // 
-      this.gradientChart.Dock = System.Windows.Forms.DockStyle.Fill;
-      this.gradientChart.DrawingSteps = 1000;
-      this.gradientChart.Location = new System.Drawing.Point(0, 0);
-      this.gradientChart.Name = "gradientChart";
-      this.gradientChart.ShowCursor = false;
-      this.gradientChart.ShowLegend = false;
-      this.gradientChart.Size = new System.Drawing.Size(715, 376);
-      this.gradientChart.TabIndex = 0;
-      this.gradientChart.XAxisTicks = 10;
-      this.gradientChart.YAxisTicks = 5;
+      this._partialDependencePlot.Dock = System.Windows.Forms.DockStyle.Fill;
+      this._partialDependencePlot.DrawingSteps = 1000;
+      this._partialDependencePlot.Location = new System.Drawing.Point(0, 0);
+      this._partialDependencePlot.Name = "_partialDependencePlot";
+      this._partialDependencePlot.ShowCursor = false;
+      this._partialDependencePlot.ShowLegend = false;
+      this._partialDependencePlot.Size = new System.Drawing.Size(715, 376);
+      this._partialDependencePlot.TabIndex = 0;
+      this._partialDependencePlot.XAxisTicks = 10;
+      this._partialDependencePlot.YAxisTicks = 5;
       // 
       // configurationGroupBox
@@ -131,5 +131,5 @@
     private System.Windows.Forms.GroupBox configurationGroupBox;
     private System.Windows.Forms.TableLayoutPanel tableLayoutPanel;
-    private Problems.DataAnalysis.Views.GradientChart gradientChart;
+    private Problems.DataAnalysis.Views.PartialDependencePlot _partialDependencePlot;
   }
 }
Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionGradientView.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionGradientView.cs	(revision 15131)
+++ stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionGradientView.cs	(revision 15137)
@@ -94,6 +94,6 @@
 
       sharedFixedVariables = new ModifiableDataset(variableNames, newTrackbars.Select(tb => new List<double>(1) { (double)tb.Value }));
-      gradientChart.Configure(new[] { Content }, sharedFixedVariables, variableNames.First(), DrawingSteps);
-      await gradientChart.RecalculateAsync();
+      _partialDependencePlot.Configure(new[] { Content }, sharedFixedVariables, variableNames.First(), DrawingSteps);
+      await _partialDependencePlot.RecalculateAsync();
 
       // Add to table and observable lists
@@ -122,6 +122,6 @@
       double axisMin, axisMax, axisInterval;
       ChartUtil.CalculateAxisInterval(min - scale * range, max + scale * range, 5, out axisMin, out axisMax, out axisInterval);
-      gradientChart.FixedYAxisMin = axisMin;
-      gradientChart.FixedYAxisMax = axisMax;
+      _partialDependencePlot.FixedYAxisMin = axisMin;
+      _partialDependencePlot.FixedYAxisMax = axisMax;
 
       trackbars.First().Checked = true;
@@ -168,6 +168,6 @@
       foreach (var tb in trackbars.Except(new[] { trackBar }))
         tb.Checked = false;
-      gradientChart.FreeVariable = variableNames[trackbars.IndexOf(trackBar)];
-      await gradientChart.RecalculateAsync();
+      _partialDependencePlot.FreeVariable = variableNames[trackbars.IndexOf(trackBar)];
+      await _partialDependencePlot.RecalculateAsync();
     }
 
@@ -175,7 +175,7 @@
       var trackBar = sender as DensityTrackbar;
       if (trackBar == null || !trackBar.Checked) return;
-      gradientChart.FixedXAxisMin = trackBar.Limits.Lower;
-      gradientChart.FixedXAxisMax = trackBar.Limits.Upper;
-      await gradientChart.RecalculateAsync();
+      _partialDependencePlot.FixedXAxisMin = trackBar.Limits.Lower;
+      _partialDependencePlot.FixedXAxisMax = trackBar.Limits.Upper;
+      await _partialDependencePlot.RecalculateAsync();
     }
 
@@ -184,5 +184,5 @@
       if (trackBar == null) return;
       sharedFixedVariables.SetVariableValue((double)trackBar.Value, variableNames[trackbars.IndexOf(trackBar)], 0);
-      await gradientChart.RecalculateAsync();
+      await _partialDependencePlot.RecalculateAsync();
     }
 
Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionPartialDependencePlotView.Designer.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionPartialDependencePlotView.Designer.cs	(revision 15137)
+++ stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionPartialDependencePlotView.Designer.cs	(revision 15137)
@@ -0,0 +1,271 @@
+﻿namespace HeuristicLab.Problems.DataAnalysis.Views {
+  partial class RegressionSolutionPartialDependencePlotView {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      this.components = new System.ComponentModel.Container();
+      this.variableListView = new System.Windows.Forms.ListView();
+      this.partialDependencePlotTableLayout = new System.Windows.Forms.TableLayoutPanel();
+      this.yAxisConfigGroupBox = new System.Windows.Forms.GroupBox();
+      this.limitView = new HeuristicLab.Problems.DataAnalysis.Views.DoubleLimitView();
+      this.automaticYAxisCheckBox = new System.Windows.Forms.CheckBox();
+      this.densityGroupBox = new System.Windows.Forms.GroupBox();
+      this.columnsLabel = new System.Windows.Forms.Label();
+      this.densityComboBox = new System.Windows.Forms.ComboBox();
+      this.label1 = new System.Windows.Forms.Label();
+      this.configSplitContainer = new System.Windows.Forms.SplitContainer();
+      this.variableGroupBox = new System.Windows.Forms.GroupBox();
+      this.scrollPanel = new System.Windows.Forms.Panel();
+      this.errorProvider = new System.Windows.Forms.ErrorProvider(this.components);
+      this.columnsNumericUpDown = new System.Windows.Forms.NumericUpDown();
+      this.yAxisConfigGroupBox.SuspendLayout();
+      this.densityGroupBox.SuspendLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.configSplitContainer)).BeginInit();
+      this.configSplitContainer.Panel1.SuspendLayout();
+      this.configSplitContainer.Panel2.SuspendLayout();
+      this.configSplitContainer.SuspendLayout();
+      this.variableGroupBox.SuspendLayout();
+      this.scrollPanel.SuspendLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
+      ((System.ComponentModel.ISupportInitialize)(this.columnsNumericUpDown)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // variableListView
+      // 
+      this.variableListView.CheckBoxes = true;
+      this.variableListView.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.variableListView.Location = new System.Drawing.Point(3, 16);
+      this.variableListView.Name = "variableListView";
+      this.variableListView.Size = new System.Drawing.Size(163, 478);
+      this.variableListView.TabIndex = 0;
+      this.variableListView.UseCompatibleStateImageBehavior = false;
+      this.variableListView.View = System.Windows.Forms.View.List;
+      this.variableListView.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.variableListView_ItemChecked);
+      // 
+      // partialDependencePlotTableLayout
+      // 
+      this.partialDependencePlotTableLayout.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.partialDependencePlotTableLayout.AutoSize = true;
+      this.partialDependencePlotTableLayout.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
+      this.partialDependencePlotTableLayout.ColumnCount = 1;
+      this.partialDependencePlotTableLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
+      this.partialDependencePlotTableLayout.Location = new System.Drawing.Point(0, 0);
+      this.partialDependencePlotTableLayout.Name = "partialDependencePlotTableLayout";
+      this.partialDependencePlotTableLayout.RowCount = 1;
+      this.partialDependencePlotTableLayout.RowStyles.Add(new System.Windows.Forms.RowStyle());
+      this.partialDependencePlotTableLayout.Size = new System.Drawing.Size(542, 0);
+      this.partialDependencePlotTableLayout.TabIndex = 2;
+      // 
+      // yAxisConfigGroupBox
+      // 
+      this.yAxisConfigGroupBox.Controls.Add(this.limitView);
+      this.yAxisConfigGroupBox.Controls.Add(this.automaticYAxisCheckBox);
+      this.yAxisConfigGroupBox.Dock = System.Windows.Forms.DockStyle.Top;
+      this.yAxisConfigGroupBox.Location = new System.Drawing.Point(0, 0);
+      this.yAxisConfigGroupBox.Name = "yAxisConfigGroupBox";
+      this.yAxisConfigGroupBox.Size = new System.Drawing.Size(169, 77);
+      this.yAxisConfigGroupBox.TabIndex = 2;
+      this.yAxisConfigGroupBox.TabStop = false;
+      this.yAxisConfigGroupBox.Text = "Y-Axis";
+      // 
+      // limitView
+      // 
+      this.limitView.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.limitView.Caption = "DoubleLimit View";
+      this.limitView.Content = null;
+      this.limitView.Location = new System.Drawing.Point(6, 20);
+      this.limitView.Name = "limitView";
+      this.limitView.ReadOnly = false;
+      this.limitView.Size = new System.Drawing.Size(157, 47);
+      this.limitView.TabIndex = 1;
+      // 
+      // automaticYAxisCheckBox
+      // 
+      this.automaticYAxisCheckBox.AutoSize = true;
+      this.automaticYAxisCheckBox.Location = new System.Drawing.Point(49, -1);
+      this.automaticYAxisCheckBox.Name = "automaticYAxisCheckBox";
+      this.automaticYAxisCheckBox.Size = new System.Drawing.Size(73, 17);
+      this.automaticYAxisCheckBox.TabIndex = 0;
+      this.automaticYAxisCheckBox.Text = "Automatic";
+      this.automaticYAxisCheckBox.UseVisualStyleBackColor = true;
+      this.automaticYAxisCheckBox.CheckedChanged += new System.EventHandler(this.automaticYAxisCheckBox_CheckedChanged);
+      // 
+      // densityGroupBox
+      // 
+      this.densityGroupBox.Controls.Add(this.columnsNumericUpDown);
+      this.densityGroupBox.Controls.Add(this.columnsLabel);
+      this.densityGroupBox.Controls.Add(this.densityComboBox);
+      this.densityGroupBox.Controls.Add(this.label1);
+      this.densityGroupBox.Dock = System.Windows.Forms.DockStyle.Top;
+      this.densityGroupBox.Location = new System.Drawing.Point(0, 77);
+      this.densityGroupBox.Name = "densityGroupBox";
+      this.densityGroupBox.Size = new System.Drawing.Size(169, 74);
+      this.densityGroupBox.TabIndex = 3;
+      this.densityGroupBox.TabStop = false;
+      this.densityGroupBox.Text = "Settings";
+      // 
+      // columnsLabel
+      // 
+      this.columnsLabel.AutoSize = true;
+      this.columnsLabel.Location = new System.Drawing.Point(7, 49);
+      this.columnsLabel.Name = "columnsLabel";
+      this.columnsLabel.Size = new System.Drawing.Size(50, 13);
+      this.columnsLabel.TabIndex = 0;
+      this.columnsLabel.Text = "Columns:";
+      // 
+      // densityComboBox
+      // 
+      this.densityComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.densityComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+      this.densityComboBox.FormattingEnabled = true;
+      this.densityComboBox.Items.AddRange(new object[] {
+            "None",
+            "Training",
+            "Test",
+            "All"});
+      this.densityComboBox.Location = new System.Drawing.Point(66, 19);
+      this.densityComboBox.Name = "densityComboBox";
+      this.densityComboBox.Size = new System.Drawing.Size(94, 21);
+      this.densityComboBox.TabIndex = 0;
+      this.densityComboBox.SelectedIndexChanged += new System.EventHandler(this.densityComboBox_SelectedIndexChanged);
+      // 
+      // label1
+      // 
+      this.label1.AutoSize = true;
+      this.label1.Location = new System.Drawing.Point(7, 22);
+      this.label1.Name = "label1";
+      this.label1.Size = new System.Drawing.Size(45, 13);
+      this.label1.TabIndex = 0;
+      this.label1.Text = "Density:";
+      // 
+      // configSplitContainer
+      // 
+      this.configSplitContainer.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.configSplitContainer.FixedPanel = System.Windows.Forms.FixedPanel.Panel1;
+      this.configSplitContainer.Location = new System.Drawing.Point(0, 0);
+      this.configSplitContainer.Name = "configSplitContainer";
+      // 
+      // configSplitContainer.Panel1
+      // 
+      this.configSplitContainer.Panel1.Controls.Add(this.variableGroupBox);
+      this.configSplitContainer.Panel1.Controls.Add(this.densityGroupBox);
+      this.configSplitContainer.Panel1.Controls.Add(this.yAxisConfigGroupBox);
+      // 
+      // configSplitContainer.Panel2
+      // 
+      this.configSplitContainer.Panel2.Controls.Add(this.scrollPanel);
+      this.configSplitContainer.Size = new System.Drawing.Size(715, 648);
+      this.configSplitContainer.SplitterDistance = 169;
+      this.configSplitContainer.TabIndex = 0;
+      this.configSplitContainer.TabStop = false;
+      // 
+      // variableGroupBox
+      // 
+      this.variableGroupBox.Controls.Add(this.variableListView);
+      this.variableGroupBox.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.variableGroupBox.Location = new System.Drawing.Point(0, 151);
+      this.variableGroupBox.Name = "variableGroupBox";
+      this.variableGroupBox.Size = new System.Drawing.Size(169, 497);
+      this.variableGroupBox.TabIndex = 1;
+      this.variableGroupBox.TabStop = false;
+      this.variableGroupBox.Text = "Variables";
+      // 
+      // scrollPanel
+      // 
+      this.scrollPanel.Controls.Add(this.partialDependencePlotTableLayout);
+      this.scrollPanel.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.scrollPanel.Location = new System.Drawing.Point(0, 0);
+      this.scrollPanel.Name = "scrollPanel";
+      this.scrollPanel.Size = new System.Drawing.Size(542, 648);
+      this.scrollPanel.TabIndex = 0;
+      // 
+      // errorProvider
+      // 
+      this.errorProvider.BlinkStyle = System.Windows.Forms.ErrorBlinkStyle.NeverBlink;
+      this.errorProvider.ContainerControl = this;
+      // 
+      // columnsNumericUpDown
+      // 
+      this.columnsNumericUpDown.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.columnsNumericUpDown.Location = new System.Drawing.Point(66, 46);
+      this.columnsNumericUpDown.Minimum = new decimal(new int[] {
+            1,
+            0,
+            0,
+            0});
+      this.columnsNumericUpDown.Name = "columnsNumericUpDown";
+      this.columnsNumericUpDown.Size = new System.Drawing.Size(94, 20);
+      this.columnsNumericUpDown.TabIndex = 1;
+      this.columnsNumericUpDown.Value = new decimal(new int[] {
+            4,
+            0,
+            0,
+            0});
+      this.columnsNumericUpDown.ValueChanged += new System.EventHandler(this.columnsNumericUpDown_ValueChanged);
+      // 
+      // RegressionSolutionPartialDependencePlotView
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Controls.Add(this.configSplitContainer);
+      this.Name = "RegressionSolutionPartialDependencePlotView";
+      this.Size = new System.Drawing.Size(715, 648);
+      this.yAxisConfigGroupBox.ResumeLayout(false);
+      this.yAxisConfigGroupBox.PerformLayout();
+      this.densityGroupBox.ResumeLayout(false);
+      this.densityGroupBox.PerformLayout();
+      this.configSplitContainer.Panel1.ResumeLayout(false);
+      this.configSplitContainer.Panel2.ResumeLayout(false);
+      ((System.ComponentModel.ISupportInitialize)(this.configSplitContainer)).EndInit();
+      this.configSplitContainer.ResumeLayout(false);
+      this.variableGroupBox.ResumeLayout(false);
+      this.scrollPanel.ResumeLayout(false);
+      this.scrollPanel.PerformLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit();
+      ((System.ComponentModel.ISupportInitialize)(this.columnsNumericUpDown)).EndInit();
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.ListView variableListView;
+    private System.Windows.Forms.TableLayoutPanel partialDependencePlotTableLayout;
+    private System.Windows.Forms.GroupBox yAxisConfigGroupBox;
+    private System.Windows.Forms.CheckBox automaticYAxisCheckBox;
+    private DoubleLimitView limitView;
+    private System.Windows.Forms.GroupBox densityGroupBox;
+    private System.Windows.Forms.ComboBox densityComboBox;
+    private System.Windows.Forms.SplitContainer configSplitContainer;
+    private System.Windows.Forms.GroupBox variableGroupBox;
+    private System.Windows.Forms.Panel scrollPanel;
+    private System.Windows.Forms.Label columnsLabel;
+    private System.Windows.Forms.ErrorProvider errorProvider;
+    private System.Windows.Forms.Label label1;
+    private System.Windows.Forms.NumericUpDown columnsNumericUpDown;
+  }
+}
Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionPartialDependencePlotView.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionPartialDependencePlotView.cs	(revision 15137)
+++ stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionPartialDependencePlotView.cs	(revision 15137)
@@ -0,0 +1,567 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Globalization;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using HeuristicLab.Common;
+using HeuristicLab.MainForm;
+using HeuristicLab.Visualization.ChartControlsExtensions;
+
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  [View("Partial Dependence Plots")]
+  [Content(typeof(IRegressionSolution))]
+  public partial class RegressionSolutionPartialDependencePlotView : DataAnalysisSolutionEvaluationView {
+    private readonly Dictionary<string, IPartialDependencePlot> partialDependencePlots;
+    private readonly Dictionary<string, DensityChart> densityCharts;
+    private readonly Dictionary<string, Panel> groupingPanels;
+    private ModifiableDataset sharedFixedVariables;
+
+    private const int Points = 200;
+    private int MaxColumns = 4;
+
+    private IEnumerable<string> VisibleVariables {
+      get {
+        foreach (ListViewItem item in variableListView.CheckedItems)
+          yield return item.Text;
+      }
+    }
+    private IEnumerable<IPartialDependencePlot> VisiblePartialDependencePlots {
+      get { return VisibleVariables.Select(v => partialDependencePlots[v]); }
+    }
+    private IEnumerable<DensityChart> VisibleDensityCharts {
+      get { return VisibleVariables.Select(v => densityCharts[v]); }
+    }
+    private IEnumerable<Panel> VisibleChartsPanels {
+      get { return VisibleVariables.Select(v => groupingPanels[v]); }
+    }
+
+    public RegressionSolutionPartialDependencePlotView() {
+      InitializeComponent();
+      partialDependencePlots = new Dictionary<string, IPartialDependencePlot>();
+      densityCharts = new Dictionary<string, DensityChart>();
+      groupingPanels = new Dictionary<string, Panel>();
+
+      limitView.Content = new DoubleLimit(0, 1);
+      limitView.Content.ValueChanged += limit_ValueChanged;
+
+      densityComboBox.SelectedIndex = 1; // select Training
+
+      // Avoid additional horizontal scrollbar
+      var vertScrollWidth = SystemInformation.VerticalScrollBarWidth;
+      scrollPanel.Padding = new Padding(0, 0, vertScrollWidth, 0);
+      scrollPanel.AutoScroll = true;
+    }
+
+    public new IRegressionSolution Content {
+      get { return (IRegressionSolution)base.Content; }
+      set { base.Content = value; }
+    }
+
+    protected override void RegisterContentEvents() {
+      base.RegisterContentEvents();
+      Content.ModelChanged += solution_ModelChanged;
+    }
+
+    protected override void DeregisterContentEvents() {
+      Content.ModelChanged -= solution_ModelChanged;
+      base.DeregisterContentEvents();
+    }
+
+    protected override void OnContentChanged() {
+      base.OnContentChanged();
+      if (Content == null) return;
+      var problemData = Content.ProblemData;
+
+      // Init Y-axis range
+      double min = double.MaxValue, max = double.MinValue;
+      var trainingTarget = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices);
+      foreach (var t in trainingTarget) {
+        if (t < min) min = t;
+        if (t > max) max = t;
+      }
+      double range = max - min;
+      const double scale = 1.0 / 3.0;
+      double axisMin, axisMax, axisInterval;
+      ChartUtil.CalculateAxisInterval(min - scale * range, max + scale * range, 5, out axisMin, out axisMax, out axisInterval);
+      automaticYAxisCheckBox.Checked = false;
+      limitView.ReadOnly = false;
+      limitView.Content.Lower = axisMin;
+      limitView.Content.Upper = axisMax;
+
+      // create dataset of problemData input variables and model input variables
+      // necessary workaround to have the variables in the occuring order
+      var inputvariables =
+        new HashSet<string>(Content.ProblemData.AllowedInputVariables.Union(Content.Model.VariablesUsedForPrediction));
+      var allowedInputVariables =
+        Content.ProblemData.Dataset.VariableNames.Where(v => inputvariables.Contains(v)).ToList();
+
+
+      var doubleVariables = allowedInputVariables.Where(problemData.Dataset.VariableHasType<double>);
+      var doubleVariableValues = (IEnumerable<IList>)doubleVariables.Select(x => new List<double> { problemData.Dataset.GetDoubleValues(x, problemData.TrainingIndices).Median() });
+
+      var factorVariables = allowedInputVariables.Where(problemData.Dataset.VariableHasType<string>);
+      var factorVariableValues = (IEnumerable<IList>)factorVariables.Select(x => new List<string> {
+        problemData.Dataset.GetStringValues(x, problemData.TrainingIndices)
+        .GroupBy(val => val).OrderByDescending(g => g.Count()).First().Key // most frequent value
+      });
+
+      if (sharedFixedVariables != null)
+        sharedFixedVariables.ItemChanged -= SharedFixedVariables_ItemChanged;
+
+      sharedFixedVariables = new ModifiableDataset(doubleVariables.Concat(factorVariables), doubleVariableValues.Concat(factorVariableValues));
+
+
+      // create controls
+      partialDependencePlots.Clear();
+      densityCharts.Clear();
+      groupingPanels.Clear();
+      foreach (var variableName in doubleVariables) {
+        var plot = CreatePartialDependencePlot(variableName, sharedFixedVariables);
+        partialDependencePlots.Add(variableName, plot);
+
+        var densityChart = new DensityChart() {
+          Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right,
+          Margin = Padding.Empty,
+          Height = 12,
+          Visible = false,
+          Top = (int)(plot.Height * 0.1),
+        };
+        densityCharts.Add(variableName, densityChart);
+
+        plot.ZoomChanged += (o, e) => {
+          var pdp = (PartialDependencePlot)o;
+          var density = densityCharts[pdp.FreeVariable];
+          density.Visible = densityComboBox.SelectedIndex != 0 && !pdp.IsZoomed;
+          if (density.Visible)
+            UpdateDensityChart(density, pdp.FreeVariable);
+        };
+        plot.SizeChanged += (o, e) => {
+          var pdp = (PartialDependencePlot)o;
+          var density = densityCharts[pdp.FreeVariable];
+          density.Top = (int)(pdp.Height * 0.1);
+        };
+
+        // Initially, the inner plot areas are not initialized for hidden charts (scollpanel, ...)
+        // This event handler listens for the paint event once (where everything is already initialized) to do some manual layouting.
+        plot.ChartPostPaint += OnPartialDependencePlotPostPaint;
+
+        var panel = new Panel() {
+          Dock = DockStyle.Fill,
+          Margin = Padding.Empty,
+          BackColor = Color.White
+        };
+
+        panel.Controls.Add(densityChart);
+        panel.Controls.Add(plot);
+        groupingPanels.Add(variableName, panel);
+      }
+      foreach (var variableName in factorVariables) {
+        var plot = CreateFactorPartialDependencePlot(variableName, sharedFixedVariables);
+        partialDependencePlots.Add(variableName, plot);
+
+        var densityChart = new DensityChart() {
+          Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right,
+          Margin = Padding.Empty,
+          Height = 12,
+          Visible = false,
+          Top = (int)(plot.Height * 0.1),
+        };
+        densityCharts.Add(variableName, densityChart);
+        plot.ZoomChanged += (o, e) => {
+          var pdp = (FactorPartialDependencePlot)o;
+          var density = densityCharts[pdp.FreeVariable];
+          density.Visible = densityComboBox.SelectedIndex != 0 && !pdp.IsZoomed;
+          if (density.Visible)
+            UpdateDensityChart(density, pdp.FreeVariable);
+        };
+        plot.SizeChanged += (o, e) => {
+          var pdp = (FactorPartialDependencePlot)o;
+          var density = densityCharts[pdp.FreeVariable];
+          density.Top = (int)(pdp.Height * 0.1);
+        };
+
+        // Initially, the inner plot areas are not initialized for hidden charts (scollpanel, ...)
+        // This event handler listens for the paint event once (where everything is already initialized) to do some manual layouting.
+        plot.ChartPostPaint += OnFactorPartialDependencePlotPostPaint;
+
+        var panel = new Panel() {
+          Dock = DockStyle.Fill,
+          Margin = Padding.Empty,
+          BackColor = Color.White
+        };
+
+        panel.Controls.Add(densityChart);
+        panel.Controls.Add(plot);
+        groupingPanels.Add(variableName, panel);
+      }
+      // update variable list
+      variableListView.ItemChecked -= variableListView_ItemChecked;
+      variableListView.Items.Clear();
+      foreach (var variable in allowedInputVariables)
+        variableListView.Items.Add(key: variable, text: variable, imageIndex: 0);
+
+      foreach (var variable in Content.Model.VariablesUsedForPrediction)
+        variableListView.Items[variable].Checked = true;
+      variableListView.ItemChecked += variableListView_ItemChecked;
+
+      sharedFixedVariables.ItemChanged += SharedFixedVariables_ItemChanged;
+
+      RecalculateAndRelayoutCharts();
+    }
+
+    private void SharedFixedVariables_ItemChanged(object sender, EventArgs<int, int> e) {
+      double yValue = Content.Model.GetEstimatedValues(sharedFixedVariables, new[] { 0 }).Single();
+      string title = Content.ProblemData.TargetVariable + ": " + yValue.ToString("G5", CultureInfo.CurrentCulture);
+      foreach (var chart in partialDependencePlots.Values) {
+        if (!string.IsNullOrEmpty(chart.YAxisTitle)) { // only show title for first column in grid
+          chart.YAxisTitle = title;
+        }
+      }
+    }
+
+
+    private void OnPartialDependencePlotPostPaint(object o, EventArgs e) {
+      var plot = (PartialDependencePlot)o;
+      var density = densityCharts[plot.FreeVariable];
+
+      density.Width = plot.Width;
+
+      var gcPlotPosition = plot.InnerPlotPosition;
+      density.Left = (int)(gcPlotPosition.X / 100.0 * plot.Width);
+      density.Width = (int)(gcPlotPosition.Width / 100.0 * plot.Width);
+      plot.UpdateTitlePosition();
+
+      // removed after succesful layouting due to performance reasons
+      if (gcPlotPosition.Width != 0)
+        plot.ChartPostPaint -= OnPartialDependencePlotPostPaint;
+    }
+
+    private void OnFactorPartialDependencePlotPostPaint(object o, EventArgs e) {
+      var plot = (FactorPartialDependencePlot)o;
+      var density = densityCharts[plot.FreeVariable];
+
+      density.Width = plot.Width;
+
+      var gcPlotPosition = plot.InnerPlotPosition;
+      density.Left = (int)(gcPlotPosition.X / 100.0 * plot.Width);
+      density.Width = (int)(gcPlotPosition.Width / 100.0 * plot.Width);
+      plot.UpdateTitlePosition();
+
+      // removed after succesful layouting due to performance reasons
+      if (gcPlotPosition.Width != 0)
+        plot.ChartPostPaint -= OnFactorPartialDependencePlotPostPaint;
+    }
+
+    private async void RecalculateAndRelayoutCharts() {
+      foreach (var variable in VisibleVariables) {
+        var plot = partialDependencePlots[variable];
+        await plot.RecalculateAsync(false, false);
+      }
+      partialDependencePlotTableLayout.SuspendLayout();
+      SetupYAxis();
+      ReOrderControls();
+      SetStyles();
+      partialDependencePlotTableLayout.ResumeLayout();
+      partialDependencePlotTableLayout.Refresh();
+      foreach (var variable in VisibleVariables) {
+        DensityChart densityChart;
+        if (densityCharts.TryGetValue(variable, out densityChart)) {
+          UpdateDensityChart(densityChart, variable);
+        }
+      }
+    }
+    private PartialDependencePlot CreatePartialDependencePlot(string variableName, ModifiableDataset sharedFixedVariables) {
+      var plot = new PartialDependencePlot {
+        Dock = DockStyle.Fill,
+        Margin = Padding.Empty,
+        ShowLegend = false,
+        ShowCursor = true,
+        ShowConfigButton = false,
+        YAxisTicks = 5,
+      };
+      plot.VariableValueChanged += async (o, e) => {
+        var recalculations = VisiblePartialDependencePlots
+          .Except(new[] { (IPartialDependencePlot)o })
+          .Select(async chart => {
+            await chart.RecalculateAsync(updateOnFinish: false, resetYAxis: false);
+          }).ToList();
+        await Task.WhenAll(recalculations);
+
+        if (recalculations.All(t => t.IsCompleted))
+          SetupYAxis();
+      };
+      plot.Configure(new[] { Content }, sharedFixedVariables, variableName, Points);
+      plot.SolutionAdded += partialDependencePlot_SolutionAdded;
+      plot.SolutionRemoved += partialDependencePlot_SolutionRemoved;
+      return plot;
+    }
+    private FactorPartialDependencePlot CreateFactorPartialDependencePlot(string variableName, ModifiableDataset sharedFixedVariables) {
+      var plot = new FactorPartialDependencePlot {
+        Dock = DockStyle.Fill,
+        Margin = Padding.Empty,
+        ShowLegend = false,
+        ShowCursor = true,
+        YAxisTicks = 5,
+      };
+      plot.VariableValueChanged += async (o, e) => {
+        var recalculations = VisiblePartialDependencePlots
+          .Except(new[] { (FactorPartialDependencePlot)o })
+          .Select(async chart => {
+            await chart.RecalculateAsync(updateOnFinish: false, resetYAxis: false);
+          }).ToList();
+        await Task.WhenAll(recalculations);
+
+        if (recalculations.All(t => t.IsCompleted))
+          SetupYAxis();
+      };
+      var variableValues = Content.ProblemData.Dataset.GetStringValues(variableName).Distinct().OrderBy(n => n).ToList();
+      plot.Configure(new[] { Content }, sharedFixedVariables, variableName, variableValues);
+      plot.SolutionAdded += partialDependencePlot_SolutionAdded;
+      plot.SolutionRemoved += partialDependencePlot_SolutionRemoved;
+      return plot;
+    }
+    private void SetupYAxis() {
+      double axisMin, axisMax;
+      if (automaticYAxisCheckBox.Checked) {
+        double min = double.MaxValue, max = double.MinValue;
+        foreach (var chart in VisiblePartialDependencePlots) {
+          if (chart.YMin < min) min = chart.YMin;
+          if (chart.YMax > max) max = chart.YMax;
+        }
+
+        double axisInterval;
+        ChartUtil.CalculateAxisInterval(min, max, 5, out axisMin, out axisMax, out axisInterval);
+      } else {
+        axisMin = limitView.Content.Lower;
+        axisMax = limitView.Content.Upper;
+      }
+
+      foreach (var chart in VisiblePartialDependencePlots) {
+        chart.FixedYAxisMin = axisMin;
+        chart.FixedYAxisMax = axisMax;
+      }
+    }
+
+    // reorder chart controls so that they always appear in the same order as in the list view
+    // the table layout containing the controls should be suspended before calling this method
+    private void ReOrderControls() {
+      var tl = partialDependencePlotTableLayout;
+      tl.Controls.Clear();
+      int row = 0, column = 0;
+      double yValue = Content.Model.GetEstimatedValues(sharedFixedVariables, new[] { 0 }).Single();
+      string title = Content.ProblemData.TargetVariable + ": " + yValue.ToString("G5", CultureInfo.CurrentCulture);
+
+      foreach (var v in VisibleVariables) {
+        var chartsPanel = groupingPanels[v];
+        tl.Controls.Add(chartsPanel, column, row);
+
+        var chart = partialDependencePlots[v];
+        chart.YAxisTitle = column == 0 ? title : string.Empty;
+        column++;
+
+        if (column == MaxColumns) {
+          row++;
+          column = 0;
+        }
+      }
+    }
+
+    private void SetStyles() {
+      var tl = partialDependencePlotTableLayout;
+      tl.RowStyles.Clear();
+      tl.ColumnStyles.Clear();
+      int numVariables = VisibleVariables.Count();
+      if (numVariables == 0)
+        return;
+
+      // set column styles
+      tl.ColumnCount = Math.Min(numVariables, MaxColumns);
+      for (int c = 0; c < tl.ColumnCount; c++)
+        tl.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100.0f / tl.ColumnCount));
+
+      // set row styles
+      tl.RowCount = (int)Math.Ceiling((double)numVariables / tl.ColumnCount);
+      var columnWidth = tl.Width / tl.ColumnCount; // assume all columns have the same width
+      var rowHeight = (int)(0.8 * columnWidth);
+      for (int r = 0; r < tl.RowCount; r++)
+        tl.RowStyles.Add(new RowStyle(SizeType.Absolute, rowHeight));
+    }
+
+    private async void partialDependencePlot_SolutionAdded(object sender, EventArgs<IRegressionSolution> e) {
+      var solution = e.Value;
+      foreach (var chart in partialDependencePlots.Values) {
+        if (sender == chart) continue;
+        await chart.AddSolutionAsync(solution);
+      }
+    }
+
+    private async void partialDependencePlot_SolutionRemoved(object sender, EventArgs<IRegressionSolution> e) {
+      var solution = e.Value;
+      foreach (var chart in partialDependencePlots.Values) {
+        if (sender == chart) continue;
+        await chart.RemoveSolutionAsync(solution);
+      }
+    }
+
+    private async void variableListView_ItemChecked(object sender, ItemCheckedEventArgs e) {
+      var item = e.Item;
+      var variable = item.Text;
+      var plot = partialDependencePlots[variable];
+      var chartsPanel = groupingPanels[variable];
+      var tl = partialDependencePlotTableLayout;
+
+      tl.SuspendLayout();
+      if (item.Checked) {
+        tl.Controls.Add(chartsPanel);
+        await plot.RecalculateAsync(false, false);
+      } else {
+        tl.Controls.Remove(chartsPanel);
+      }
+
+      if (tl.Controls.Count > 0) {
+        SetupYAxis();
+        ReOrderControls();
+        SetStyles();
+      }
+      tl.ResumeLayout();
+      tl.Refresh();
+      densityComboBox_SelectedIndexChanged(this, EventArgs.Empty);
+    }
+
+    private void automaticYAxisCheckBox_CheckedChanged(object sender, EventArgs e) {
+      limitView.ReadOnly = automaticYAxisCheckBox.Checked;
+      SetupYAxis();
+      partialDependencePlotTableLayout.Refresh();
+      densityComboBox_SelectedIndexChanged(this, EventArgs.Empty); // necessary to realign the density plots
+    }
+
+    private void limit_ValueChanged(object sender, EventArgs e) {
+      if (automaticYAxisCheckBox.Checked)
+        return;
+      SetupYAxis();
+      partialDependencePlotTableLayout.Refresh();
+      densityComboBox_SelectedIndexChanged(this, EventArgs.Empty); // necessary to realign the density plots
+    }
+
+    private void densityComboBox_SelectedIndexChanged(object sender, EventArgs e) {
+      if (Content == null)
+        return;
+
+      int si = densityComboBox.SelectedIndex;
+      if (si == 0) {
+        foreach (var densityChart in densityCharts.Values)
+          densityChart.Visible = false;
+      } else {
+        var indices = GetDensityIndices(si).ToList();
+
+        foreach (var entry in densityCharts) {
+          var variableName = entry.Key;
+          var densityChart = entry.Value;
+          if (!VisibleVariables.Contains(variableName) || partialDependencePlots[variableName].IsZoomed)
+            continue;
+
+          UpdateDensityChart(densityChart, variableName, indices);
+        }
+      }
+    }
+    private IEnumerable<int> GetDensityIndices(int selectedIndex) {
+      var problemData = Content.ProblemData;
+      return
+        selectedIndex == 1 ? problemData.TrainingIndices :
+        selectedIndex == 2 ? problemData.TestIndices :
+        problemData.AllIndices;
+    }
+    private void UpdateDensityChart(DensityChart densityChart, string variable, IList<int> indices = null) {
+      if (densityComboBox.SelectedIndex == 0)
+        return;
+      if (indices == null) {
+        indices = GetDensityIndices(densityComboBox.SelectedIndex).ToList();
+      }
+      if (Content.ProblemData.Dataset.VariableHasType<double>(variable)) {
+        var data = Content.ProblemData.Dataset.GetDoubleValues(variable, indices).ToList();
+        var plot = partialDependencePlots[variable] as PartialDependencePlot;
+        if (plot != null) {
+          var min = plot.FixedXAxisMin;
+          var max = plot.FixedXAxisMax;
+          var buckets = plot.DrawingSteps;
+          if (min.HasValue && max.HasValue) {
+            densityChart.UpdateChart(data, min.Value, max.Value, buckets);
+            densityChart.Width = plot.Width;
+
+            var gcPlotPosition = plot.InnerPlotPosition;
+            densityChart.Left = (int)(gcPlotPosition.X / 100.0 * plot.Width);
+            densityChart.Width = (int)(gcPlotPosition.Width / 100.0 * plot.Width);
+
+            densityChart.Visible = true;
+          }
+          plot.UpdateTitlePosition();
+        }
+      } else if (Content.ProblemData.Dataset.VariableHasType<string>(variable)) {
+        var data = Content.ProblemData.Dataset.GetStringValues(variable).ToList();
+        var plot = partialDependencePlots[variable] as FactorPartialDependencePlot;
+        if (plot != null) {
+          densityChart.UpdateChart(data);
+          densityChart.Width = plot.Width;
+
+          var gcPlotPosition = plot.InnerPlotPosition;
+          densityChart.Left = (int)(gcPlotPosition.X / 100.0 * plot.Width);
+          densityChart.Width = (int)(gcPlotPosition.Width / 100.0 * plot.Width);
+
+          densityChart.Visible = true;
+
+          plot.UpdateTitlePosition();
+        }
+      }
+    }
+
+    private void columnsNumericUpDown_ValueChanged(object sender, EventArgs e) {
+      MaxColumns = (int)columnsNumericUpDown.Value;
+      int columns = Math.Min(VisibleVariables.Count(), MaxColumns);
+      if (columns > 0) {
+        var tl = partialDependencePlotTableLayout;
+        MaxColumns = columns;
+        tl.SuspendLayout();
+        ReOrderControls();
+        SetStyles();
+        tl.ResumeLayout();
+        tl.Refresh();
+        densityComboBox_SelectedIndexChanged(this, EventArgs.Empty);
+      }
+    }
+
+    private async void solution_ModelChanged(object sender, EventArgs e) {
+      foreach (var variable in VisibleVariables) {
+        var pdp = partialDependencePlots[variable];
+        var densityChart = densityCharts[variable];
+        // recalculate and refresh
+        await pdp.RecalculateAsync(false, false);
+        pdp.Refresh();
+        UpdateDensityChart(densityChart, variable);
+      }
+    }
+  }
+}
Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionTargetResponseGradientView.Designer.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionTargetResponseGradientView.Designer.cs	(revision 15131)
+++ 	(revision )
@@ -1,271 +1,0 @@
-﻿namespace HeuristicLab.Problems.DataAnalysis.Views {
-  partial class RegressionSolutionTargetResponseGradientView {
-    /// <summary> 
-    /// Required designer variable.
-    /// </summary>
-    private System.ComponentModel.IContainer components = null;
-
-    /// <summary> 
-    /// Clean up any resources being used.
-    /// </summary>
-    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
-    protected override void Dispose(bool disposing) {
-      if (disposing && (components != null)) {
-        components.Dispose();
-      }
-      base.Dispose(disposing);
-    }
-
-    #region Component Designer generated code
-
-    /// <summary> 
-    /// Required method for Designer support - do not modify 
-    /// the contents of this method with the code editor.
-    /// </summary>
-    private void InitializeComponent() {
-      this.components = new System.ComponentModel.Container();
-      this.variableListView = new System.Windows.Forms.ListView();
-      this.gradientChartTableLayout = new System.Windows.Forms.TableLayoutPanel();
-      this.yAxisConfigGroupBox = new System.Windows.Forms.GroupBox();
-      this.limitView = new HeuristicLab.Problems.DataAnalysis.Views.DoubleLimitView();
-      this.automaticYAxisCheckBox = new System.Windows.Forms.CheckBox();
-      this.densityGroupBox = new System.Windows.Forms.GroupBox();
-      this.columnsLabel = new System.Windows.Forms.Label();
-      this.densityComboBox = new System.Windows.Forms.ComboBox();
-      this.label1 = new System.Windows.Forms.Label();
-      this.configSplitContainer = new System.Windows.Forms.SplitContainer();
-      this.variableGroupBox = new System.Windows.Forms.GroupBox();
-      this.scrollPanel = new System.Windows.Forms.Panel();
-      this.errorProvider = new System.Windows.Forms.ErrorProvider(this.components);
-      this.columnsNumericUpDown = new System.Windows.Forms.NumericUpDown();
-      this.yAxisConfigGroupBox.SuspendLayout();
-      this.densityGroupBox.SuspendLayout();
-      ((System.ComponentModel.ISupportInitialize)(this.configSplitContainer)).BeginInit();
-      this.configSplitContainer.Panel1.SuspendLayout();
-      this.configSplitContainer.Panel2.SuspendLayout();
-      this.configSplitContainer.SuspendLayout();
-      this.variableGroupBox.SuspendLayout();
-      this.scrollPanel.SuspendLayout();
-      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
-      ((System.ComponentModel.ISupportInitialize)(this.columnsNumericUpDown)).BeginInit();
-      this.SuspendLayout();
-      // 
-      // variableListView
-      // 
-      this.variableListView.CheckBoxes = true;
-      this.variableListView.Dock = System.Windows.Forms.DockStyle.Fill;
-      this.variableListView.Location = new System.Drawing.Point(3, 16);
-      this.variableListView.Name = "variableListView";
-      this.variableListView.Size = new System.Drawing.Size(163, 478);
-      this.variableListView.TabIndex = 0;
-      this.variableListView.UseCompatibleStateImageBehavior = false;
-      this.variableListView.View = System.Windows.Forms.View.List;
-      this.variableListView.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.variableListView_ItemChecked);
-      // 
-      // gradientChartTableLayout
-      // 
-      this.gradientChartTableLayout.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.gradientChartTableLayout.AutoSize = true;
-      this.gradientChartTableLayout.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
-      this.gradientChartTableLayout.ColumnCount = 1;
-      this.gradientChartTableLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
-      this.gradientChartTableLayout.Location = new System.Drawing.Point(0, 0);
-      this.gradientChartTableLayout.Name = "gradientChartTableLayout";
-      this.gradientChartTableLayout.RowCount = 1;
-      this.gradientChartTableLayout.RowStyles.Add(new System.Windows.Forms.RowStyle());
-      this.gradientChartTableLayout.Size = new System.Drawing.Size(542, 0);
-      this.gradientChartTableLayout.TabIndex = 2;
-      // 
-      // yAxisConfigGroupBox
-      // 
-      this.yAxisConfigGroupBox.Controls.Add(this.limitView);
-      this.yAxisConfigGroupBox.Controls.Add(this.automaticYAxisCheckBox);
-      this.yAxisConfigGroupBox.Dock = System.Windows.Forms.DockStyle.Top;
-      this.yAxisConfigGroupBox.Location = new System.Drawing.Point(0, 0);
-      this.yAxisConfigGroupBox.Name = "yAxisConfigGroupBox";
-      this.yAxisConfigGroupBox.Size = new System.Drawing.Size(169, 77);
-      this.yAxisConfigGroupBox.TabIndex = 2;
-      this.yAxisConfigGroupBox.TabStop = false;
-      this.yAxisConfigGroupBox.Text = "Y-Axis";
-      // 
-      // limitView
-      // 
-      this.limitView.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.limitView.Caption = "DoubleLimit View";
-      this.limitView.Content = null;
-      this.limitView.Location = new System.Drawing.Point(6, 20);
-      this.limitView.Name = "limitView";
-      this.limitView.ReadOnly = false;
-      this.limitView.Size = new System.Drawing.Size(157, 47);
-      this.limitView.TabIndex = 1;
-      // 
-      // automaticYAxisCheckBox
-      // 
-      this.automaticYAxisCheckBox.AutoSize = true;
-      this.automaticYAxisCheckBox.Location = new System.Drawing.Point(49, -1);
-      this.automaticYAxisCheckBox.Name = "automaticYAxisCheckBox";
-      this.automaticYAxisCheckBox.Size = new System.Drawing.Size(73, 17);
-      this.automaticYAxisCheckBox.TabIndex = 0;
-      this.automaticYAxisCheckBox.Text = "Automatic";
-      this.automaticYAxisCheckBox.UseVisualStyleBackColor = true;
-      this.automaticYAxisCheckBox.CheckedChanged += new System.EventHandler(this.automaticYAxisCheckBox_CheckedChanged);
-      // 
-      // densityGroupBox
-      // 
-      this.densityGroupBox.Controls.Add(this.columnsNumericUpDown);
-      this.densityGroupBox.Controls.Add(this.columnsLabel);
-      this.densityGroupBox.Controls.Add(this.densityComboBox);
-      this.densityGroupBox.Controls.Add(this.label1);
-      this.densityGroupBox.Dock = System.Windows.Forms.DockStyle.Top;
-      this.densityGroupBox.Location = new System.Drawing.Point(0, 77);
-      this.densityGroupBox.Name = "densityGroupBox";
-      this.densityGroupBox.Size = new System.Drawing.Size(169, 74);
-      this.densityGroupBox.TabIndex = 3;
-      this.densityGroupBox.TabStop = false;
-      this.densityGroupBox.Text = "Settings";
-      // 
-      // columnsLabel
-      // 
-      this.columnsLabel.AutoSize = true;
-      this.columnsLabel.Location = new System.Drawing.Point(7, 49);
-      this.columnsLabel.Name = "columnsLabel";
-      this.columnsLabel.Size = new System.Drawing.Size(50, 13);
-      this.columnsLabel.TabIndex = 0;
-      this.columnsLabel.Text = "Columns:";
-      // 
-      // densityComboBox
-      // 
-      this.densityComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.densityComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
-      this.densityComboBox.FormattingEnabled = true;
-      this.densityComboBox.Items.AddRange(new object[] {
-            "None",
-            "Training",
-            "Test",
-            "All"});
-      this.densityComboBox.Location = new System.Drawing.Point(66, 19);
-      this.densityComboBox.Name = "densityComboBox";
-      this.densityComboBox.Size = new System.Drawing.Size(94, 21);
-      this.densityComboBox.TabIndex = 0;
-      this.densityComboBox.SelectedIndexChanged += new System.EventHandler(this.densityComboBox_SelectedIndexChanged);
-      // 
-      // label1
-      // 
-      this.label1.AutoSize = true;
-      this.label1.Location = new System.Drawing.Point(7, 22);
-      this.label1.Name = "label1";
-      this.label1.Size = new System.Drawing.Size(45, 13);
-      this.label1.TabIndex = 0;
-      this.label1.Text = "Density:";
-      // 
-      // configSplitContainer
-      // 
-      this.configSplitContainer.Dock = System.Windows.Forms.DockStyle.Fill;
-      this.configSplitContainer.FixedPanel = System.Windows.Forms.FixedPanel.Panel1;
-      this.configSplitContainer.Location = new System.Drawing.Point(0, 0);
-      this.configSplitContainer.Name = "configSplitContainer";
-      // 
-      // configSplitContainer.Panel1
-      // 
-      this.configSplitContainer.Panel1.Controls.Add(this.variableGroupBox);
-      this.configSplitContainer.Panel1.Controls.Add(this.densityGroupBox);
-      this.configSplitContainer.Panel1.Controls.Add(this.yAxisConfigGroupBox);
-      // 
-      // configSplitContainer.Panel2
-      // 
-      this.configSplitContainer.Panel2.Controls.Add(this.scrollPanel);
-      this.configSplitContainer.Size = new System.Drawing.Size(715, 648);
-      this.configSplitContainer.SplitterDistance = 169;
-      this.configSplitContainer.TabIndex = 0;
-      this.configSplitContainer.TabStop = false;
-      // 
-      // variableGroupBox
-      // 
-      this.variableGroupBox.Controls.Add(this.variableListView);
-      this.variableGroupBox.Dock = System.Windows.Forms.DockStyle.Fill;
-      this.variableGroupBox.Location = new System.Drawing.Point(0, 151);
-      this.variableGroupBox.Name = "variableGroupBox";
-      this.variableGroupBox.Size = new System.Drawing.Size(169, 497);
-      this.variableGroupBox.TabIndex = 1;
-      this.variableGroupBox.TabStop = false;
-      this.variableGroupBox.Text = "Variables";
-      // 
-      // scrollPanel
-      // 
-      this.scrollPanel.Controls.Add(this.gradientChartTableLayout);
-      this.scrollPanel.Dock = System.Windows.Forms.DockStyle.Fill;
-      this.scrollPanel.Location = new System.Drawing.Point(0, 0);
-      this.scrollPanel.Name = "scrollPanel";
-      this.scrollPanel.Size = new System.Drawing.Size(542, 648);
-      this.scrollPanel.TabIndex = 0;
-      // 
-      // errorProvider
-      // 
-      this.errorProvider.BlinkStyle = System.Windows.Forms.ErrorBlinkStyle.NeverBlink;
-      this.errorProvider.ContainerControl = this;
-      // 
-      // columnsNumericUpDown
-      // 
-      this.columnsNumericUpDown.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.columnsNumericUpDown.Location = new System.Drawing.Point(66, 46);
-      this.columnsNumericUpDown.Minimum = new decimal(new int[] {
-            1,
-            0,
-            0,
-            0});
-      this.columnsNumericUpDown.Name = "columnsNumericUpDown";
-      this.columnsNumericUpDown.Size = new System.Drawing.Size(94, 20);
-      this.columnsNumericUpDown.TabIndex = 1;
-      this.columnsNumericUpDown.Value = new decimal(new int[] {
-            4,
-            0,
-            0,
-            0});
-      this.columnsNumericUpDown.ValueChanged += new System.EventHandler(this.columnsNumericUpDown_ValueChanged);
-      // 
-      // RegressionSolutionTargetResponseGradientView
-      // 
-      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-      this.Controls.Add(this.configSplitContainer);
-      this.Name = "RegressionSolutionTargetResponseGradientView";
-      this.Size = new System.Drawing.Size(715, 648);
-      this.yAxisConfigGroupBox.ResumeLayout(false);
-      this.yAxisConfigGroupBox.PerformLayout();
-      this.densityGroupBox.ResumeLayout(false);
-      this.densityGroupBox.PerformLayout();
-      this.configSplitContainer.Panel1.ResumeLayout(false);
-      this.configSplitContainer.Panel2.ResumeLayout(false);
-      ((System.ComponentModel.ISupportInitialize)(this.configSplitContainer)).EndInit();
-      this.configSplitContainer.ResumeLayout(false);
-      this.variableGroupBox.ResumeLayout(false);
-      this.scrollPanel.ResumeLayout(false);
-      this.scrollPanel.PerformLayout();
-      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit();
-      ((System.ComponentModel.ISupportInitialize)(this.columnsNumericUpDown)).EndInit();
-      this.ResumeLayout(false);
-
-    }
-
-    #endregion
-
-    private System.Windows.Forms.ListView variableListView;
-    private System.Windows.Forms.TableLayoutPanel gradientChartTableLayout;
-    private System.Windows.Forms.GroupBox yAxisConfigGroupBox;
-    private System.Windows.Forms.CheckBox automaticYAxisCheckBox;
-    private DoubleLimitView limitView;
-    private System.Windows.Forms.GroupBox densityGroupBox;
-    private System.Windows.Forms.ComboBox densityComboBox;
-    private System.Windows.Forms.SplitContainer configSplitContainer;
-    private System.Windows.Forms.GroupBox variableGroupBox;
-    private System.Windows.Forms.Panel scrollPanel;
-    private System.Windows.Forms.Label columnsLabel;
-    private System.Windows.Forms.ErrorProvider errorProvider;
-    private System.Windows.Forms.Label label1;
-    private System.Windows.Forms.NumericUpDown columnsNumericUpDown;
-  }
-}
Index: stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionTargetResponseGradientView.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionTargetResponseGradientView.cs	(revision 15131)
+++ 	(revision )
@@ -1,567 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Globalization;
-using System.Linq;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-using HeuristicLab.Common;
-using HeuristicLab.MainForm;
-using HeuristicLab.Visualization.ChartControlsExtensions;
-
-namespace HeuristicLab.Problems.DataAnalysis.Views {
-  [View("Target Response Gradients")]
-  [Content(typeof(IRegressionSolution))]
-  public partial class RegressionSolutionTargetResponseGradientView : DataAnalysisSolutionEvaluationView {
-    private readonly Dictionary<string, IGradientChart> gradientCharts;
-    private readonly Dictionary<string, DensityChart> densityCharts;
-    private readonly Dictionary<string, Panel> groupingPanels;
-    private ModifiableDataset sharedFixedVariables;
-
-    private const int Points = 200;
-    private int MaxColumns = 4;
-
-    private IEnumerable<string> VisibleVariables {
-      get {
-        foreach (ListViewItem item in variableListView.CheckedItems)
-          yield return item.Text;
-      }
-    }
-    private IEnumerable<IGradientChart> VisibleGradientCharts {
-      get { return VisibleVariables.Select(v => gradientCharts[v]); }
-    }
-    private IEnumerable<DensityChart> VisibleDensityCharts {
-      get { return VisibleVariables.Select(v => densityCharts[v]); }
-    }
-    private IEnumerable<Panel> VisibleChartsPanels {
-      get { return VisibleVariables.Select(v => groupingPanels[v]); }
-    }
-
-    public RegressionSolutionTargetResponseGradientView() {
-      InitializeComponent();
-      gradientCharts = new Dictionary<string, IGradientChart>();
-      densityCharts = new Dictionary<string, DensityChart>();
-      groupingPanels = new Dictionary<string, Panel>();
-
-      limitView.Content = new DoubleLimit(0, 1);
-      limitView.Content.ValueChanged += limit_ValueChanged;
-
-      densityComboBox.SelectedIndex = 1; // select Training
-
-      // Avoid additional horizontal scrollbar
-      var vertScrollWidth = SystemInformation.VerticalScrollBarWidth;
-      scrollPanel.Padding = new Padding(0, 0, vertScrollWidth, 0);
-      scrollPanel.AutoScroll = true;
-    }
-
-    public new IRegressionSolution Content {
-      get { return (IRegressionSolution)base.Content; }
-      set { base.Content = value; }
-    }
-
-    protected override void RegisterContentEvents() {
-      base.RegisterContentEvents();
-      Content.ModelChanged += solution_ModelChanged;
-    }
-
-    protected override void DeregisterContentEvents() {
-      Content.ModelChanged -= solution_ModelChanged;
-      base.DeregisterContentEvents();
-    }
-
-    protected override void OnContentChanged() {
-      base.OnContentChanged();
-      if (Content == null) return;
-      var problemData = Content.ProblemData;
-
-      // Init Y-axis range
-      double min = double.MaxValue, max = double.MinValue;
-      var trainingTarget = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices);
-      foreach (var t in trainingTarget) {
-        if (t < min) min = t;
-        if (t > max) max = t;
-      }
-      double range = max - min;
-      const double scale = 1.0 / 3.0;
-      double axisMin, axisMax, axisInterval;
-      ChartUtil.CalculateAxisInterval(min - scale * range, max + scale * range, 5, out axisMin, out axisMax, out axisInterval);
-      automaticYAxisCheckBox.Checked = false;
-      limitView.ReadOnly = false;
-      limitView.Content.Lower = axisMin;
-      limitView.Content.Upper = axisMax;
-
-      // create dataset of problemData input variables and model input variables
-      // necessary workaround to have the variables in the occuring order
-      var inputvariables =
-        new HashSet<string>(Content.ProblemData.AllowedInputVariables.Union(Content.Model.VariablesUsedForPrediction));
-      var allowedInputVariables =
-        Content.ProblemData.Dataset.VariableNames.Where(v => inputvariables.Contains(v)).ToList();
-
-
-      var doubleVariables = allowedInputVariables.Where(problemData.Dataset.VariableHasType<double>);
-      var doubleVariableValues = (IEnumerable<IList>)doubleVariables.Select(x => new List<double> { problemData.Dataset.GetDoubleValues(x, problemData.TrainingIndices).Median() });
-
-      var factorVariables = allowedInputVariables.Where(problemData.Dataset.VariableHasType<string>);
-      var factorVariableValues = (IEnumerable<IList>)factorVariables.Select(x => new List<string> {
-        problemData.Dataset.GetStringValues(x, problemData.TrainingIndices)
-        .GroupBy(val => val).OrderByDescending(g => g.Count()).First().Key // most frequent value
-      });
-
-      if (sharedFixedVariables != null)
-        sharedFixedVariables.ItemChanged -= SharedFixedVariables_ItemChanged;
-
-      sharedFixedVariables = new ModifiableDataset(doubleVariables.Concat(factorVariables), doubleVariableValues.Concat(factorVariableValues));
-
-
-      // create controls
-      gradientCharts.Clear();
-      densityCharts.Clear();
-      groupingPanels.Clear();
-      foreach (var variableName in doubleVariables) {
-        var gradientChart = CreateGradientChart(variableName, sharedFixedVariables);
-        gradientCharts.Add(variableName, gradientChart);
-
-        var densityChart = new DensityChart() {
-          Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right,
-          Margin = Padding.Empty,
-          Height = 12,
-          Visible = false,
-          Top = (int)(gradientChart.Height * 0.1),
-        };
-        densityCharts.Add(variableName, densityChart);
-
-        gradientChart.ZoomChanged += (o, e) => {
-          var gradient = (GradientChart)o;
-          var density = densityCharts[gradient.FreeVariable];
-          density.Visible = densityComboBox.SelectedIndex != 0 && !gradient.IsZoomed;
-          if (density.Visible)
-            UpdateDensityChart(density, gradient.FreeVariable);
-        };
-        gradientChart.SizeChanged += (o, e) => {
-          var gradient = (GradientChart)o;
-          var density = densityCharts[gradient.FreeVariable];
-          density.Top = (int)(gradient.Height * 0.1);
-        };
-
-        // Initially, the inner plot areas are not initialized for hidden charts (scollpanel, ...)
-        // This event handler listens for the paint event once (where everything is already initialized) to do some manual layouting.
-        gradientChart.ChartPostPaint += OnGradientChartPostPaint;
-
-        var panel = new Panel() {
-          Dock = DockStyle.Fill,
-          Margin = Padding.Empty,
-          BackColor = Color.White
-        };
-
-        panel.Controls.Add(densityChart);
-        panel.Controls.Add(gradientChart);
-        groupingPanels.Add(variableName, panel);
-      }
-      foreach (var variableName in factorVariables) {
-        var gradientChart = CreateFactorGradientChart(variableName, sharedFixedVariables);
-        gradientCharts.Add(variableName, gradientChart);
-
-        var densityChart = new DensityChart() {
-          Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right,
-          Margin = Padding.Empty,
-          Height = 12,
-          Visible = false,
-          Top = (int)(gradientChart.Height * 0.1),
-        };
-        densityCharts.Add(variableName, densityChart);
-        gradientChart.ZoomChanged += (o, e) => {
-          var gradient = (FactorGradientChart)o;
-          var density = densityCharts[gradient.FreeVariable];
-          density.Visible = densityComboBox.SelectedIndex != 0 && !gradient.IsZoomed;
-          if (density.Visible)
-            UpdateDensityChart(density, gradient.FreeVariable);
-        };
-        gradientChart.SizeChanged += (o, e) => {
-          var gradient = (FactorGradientChart)o;
-          var density = densityCharts[gradient.FreeVariable];
-          density.Top = (int)(gradient.Height * 0.1);
-        };
-
-        // Initially, the inner plot areas are not initialized for hidden charts (scollpanel, ...)
-        // This event handler listens for the paint event once (where everything is already initialized) to do some manual layouting.
-        gradientChart.ChartPostPaint += OnFactorGradientChartPostPaint;
-
-        var panel = new Panel() {
-          Dock = DockStyle.Fill,
-          Margin = Padding.Empty,
-          BackColor = Color.White
-        };
-
-        panel.Controls.Add(densityChart);
-        panel.Controls.Add(gradientChart);
-        groupingPanels.Add(variableName, panel);
-      }
-      // update variable list
-      variableListView.ItemChecked -= variableListView_ItemChecked;
-      variableListView.Items.Clear();
-      foreach (var variable in allowedInputVariables)
-        variableListView.Items.Add(key: variable, text: variable, imageIndex: 0);
-
-      foreach (var variable in Content.Model.VariablesUsedForPrediction)
-        variableListView.Items[variable].Checked = true;
-      variableListView.ItemChecked += variableListView_ItemChecked;
-
-      sharedFixedVariables.ItemChanged += SharedFixedVariables_ItemChanged;
-
-      RecalculateAndRelayoutCharts();
-    }
-
-    private void SharedFixedVariables_ItemChanged(object sender, EventArgs<int, int> e) {
-      double yValue = Content.Model.GetEstimatedValues(sharedFixedVariables, new[] { 0 }).Single();
-      string title = Content.ProblemData.TargetVariable + ": " + yValue.ToString("G5", CultureInfo.CurrentCulture);
-      foreach (var chart in gradientCharts.Values) {
-        if (!string.IsNullOrEmpty(chart.YAxisTitle)) { // only show title for first column in grid
-          chart.YAxisTitle = title;
-        }
-      }
-    }
-
-
-    private void OnGradientChartPostPaint(object o, EventArgs e) {
-      var gradient = (GradientChart)o;
-      var density = densityCharts[gradient.FreeVariable];
-
-      density.Width = gradient.Width;
-
-      var gcPlotPosition = gradient.InnerPlotPosition;
-      density.Left = (int)(gcPlotPosition.X / 100.0 * gradient.Width);
-      density.Width = (int)(gcPlotPosition.Width / 100.0 * gradient.Width);
-      gradient.UpdateTitlePosition();
-
-      // removed after succesful layouting due to performance reasons
-      if (gcPlotPosition.Width != 0)
-        gradient.ChartPostPaint -= OnGradientChartPostPaint;
-    }
-
-    private void OnFactorGradientChartPostPaint(object o, EventArgs e) {
-      var gradient = (FactorGradientChart)o;
-      var density = densityCharts[gradient.FreeVariable];
-
-      density.Width = gradient.Width;
-
-      var gcPlotPosition = gradient.InnerPlotPosition;
-      density.Left = (int)(gcPlotPosition.X / 100.0 * gradient.Width);
-      density.Width = (int)(gcPlotPosition.Width / 100.0 * gradient.Width);
-      gradient.UpdateTitlePosition();
-
-      // removed after succesful layouting due to performance reasons
-      if (gcPlotPosition.Width != 0)
-        gradient.ChartPostPaint -= OnFactorGradientChartPostPaint;
-    }
-
-    private async void RecalculateAndRelayoutCharts() {
-      foreach (var variable in VisibleVariables) {
-        var gradientChart = gradientCharts[variable];
-        await gradientChart.RecalculateAsync(false, false);
-      }
-      gradientChartTableLayout.SuspendLayout();
-      SetupYAxis();
-      ReOrderControls();
-      SetStyles();
-      gradientChartTableLayout.ResumeLayout();
-      gradientChartTableLayout.Refresh();
-      foreach (var variable in VisibleVariables) {
-        DensityChart densityChart;
-        if (densityCharts.TryGetValue(variable, out densityChart)) {
-          UpdateDensityChart(densityChart, variable);
-        }
-      }
-    }
-    private GradientChart CreateGradientChart(string variableName, ModifiableDataset sharedFixedVariables) {
-      var gradientChart = new GradientChart {
-        Dock = DockStyle.Fill,
-        Margin = Padding.Empty,
-        ShowLegend = false,
-        ShowCursor = true,
-        ShowConfigButton = false,
-        YAxisTicks = 5,
-      };
-      gradientChart.VariableValueChanged += async (o, e) => {
-        var recalculations = VisibleGradientCharts
-          .Except(new[] { (IGradientChart)o })
-          .Select(async chart => {
-            await chart.RecalculateAsync(updateOnFinish: false, resetYAxis: false);
-          }).ToList();
-        await Task.WhenAll(recalculations);
-
-        if (recalculations.All(t => t.IsCompleted))
-          SetupYAxis();
-      };
-      gradientChart.Configure(new[] { Content }, sharedFixedVariables, variableName, Points);
-      gradientChart.SolutionAdded += gradientChart_SolutionAdded;
-      gradientChart.SolutionRemoved += gradientChart_SolutionRemoved;
-      return gradientChart;
-    }
-    private FactorGradientChart CreateFactorGradientChart(string variableName, ModifiableDataset sharedFixedVariables) {
-      var gradientChart = new FactorGradientChart {
-        Dock = DockStyle.Fill,
-        Margin = Padding.Empty,
-        ShowLegend = false,
-        ShowCursor = true,
-        YAxisTicks = 5,
-      };
-      gradientChart.VariableValueChanged += async (o, e) => {
-        var recalculations = VisibleGradientCharts
-          .Except(new[] { (FactorGradientChart)o })
-          .Select(async chart => {
-            await chart.RecalculateAsync(updateOnFinish: false, resetYAxis: false);
-          }).ToList();
-        await Task.WhenAll(recalculations);
-
-        if (recalculations.All(t => t.IsCompleted))
-          SetupYAxis();
-      };
-      var variableValues = Content.ProblemData.Dataset.GetStringValues(variableName).Distinct().OrderBy(n => n).ToList();
-      gradientChart.Configure(new[] { Content }, sharedFixedVariables, variableName, variableValues);
-      gradientChart.SolutionAdded += gradientChart_SolutionAdded;
-      gradientChart.SolutionRemoved += gradientChart_SolutionRemoved;
-      return gradientChart;
-    }
-    private void SetupYAxis() {
-      double axisMin, axisMax;
-      if (automaticYAxisCheckBox.Checked) {
-        double min = double.MaxValue, max = double.MinValue;
-        foreach (var chart in VisibleGradientCharts) {
-          if (chart.YMin < min) min = chart.YMin;
-          if (chart.YMax > max) max = chart.YMax;
-        }
-
-        double axisInterval;
-        ChartUtil.CalculateAxisInterval(min, max, 5, out axisMin, out axisMax, out axisInterval);
-      } else {
-        axisMin = limitView.Content.Lower;
-        axisMax = limitView.Content.Upper;
-      }
-
-      foreach (var chart in VisibleGradientCharts) {
-        chart.FixedYAxisMin = axisMin;
-        chart.FixedYAxisMax = axisMax;
-      }
-    }
-
-    // reorder chart controls so that they always appear in the same order as in the list view
-    // the table layout containing the controls should be suspended before calling this method
-    private void ReOrderControls() {
-      var tl = gradientChartTableLayout;
-      tl.Controls.Clear();
-      int row = 0, column = 0;
-      double yValue = Content.Model.GetEstimatedValues(sharedFixedVariables, new[] { 0 }).Single();
-      string title = Content.ProblemData.TargetVariable + ": " + yValue.ToString("G5", CultureInfo.CurrentCulture);
-
-      foreach (var v in VisibleVariables) {
-        var chartsPanel = groupingPanels[v];
-        tl.Controls.Add(chartsPanel, column, row);
-
-        var chart = gradientCharts[v];
-        chart.YAxisTitle = column == 0 ? title : string.Empty;
-        column++;
-
-        if (column == MaxColumns) {
-          row++;
-          column = 0;
-        }
-      }
-    }
-
-    private void SetStyles() {
-      var tl = gradientChartTableLayout;
-      tl.RowStyles.Clear();
-      tl.ColumnStyles.Clear();
-      int numVariables = VisibleVariables.Count();
-      if (numVariables == 0)
-        return;
-
-      // set column styles
-      tl.ColumnCount = Math.Min(numVariables, MaxColumns);
-      for (int c = 0; c < tl.ColumnCount; c++)
-        tl.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100.0f / tl.ColumnCount));
-
-      // set row styles
-      tl.RowCount = (int)Math.Ceiling((double)numVariables / tl.ColumnCount);
-      var columnWidth = tl.Width / tl.ColumnCount; // assume all columns have the same width
-      var rowHeight = (int)(0.8 * columnWidth);
-      for (int r = 0; r < tl.RowCount; r++)
-        tl.RowStyles.Add(new RowStyle(SizeType.Absolute, rowHeight));
-    }
-
-    private async void gradientChart_SolutionAdded(object sender, EventArgs<IRegressionSolution> e) {
-      var solution = e.Value;
-      foreach (var chart in gradientCharts.Values) {
-        if (sender == chart) continue;
-        await chart.AddSolutionAsync(solution);
-      }
-    }
-
-    private async void gradientChart_SolutionRemoved(object sender, EventArgs<IRegressionSolution> e) {
-      var solution = e.Value;
-      foreach (var chart in gradientCharts.Values) {
-        if (sender == chart) continue;
-        await chart.RemoveSolutionAsync(solution);
-      }
-    }
-
-    private async void variableListView_ItemChecked(object sender, ItemCheckedEventArgs e) {
-      var item = e.Item;
-      var variable = item.Text;
-      var gradientChart = gradientCharts[variable];
-      var chartsPanel = groupingPanels[variable];
-      var tl = gradientChartTableLayout;
-
-      tl.SuspendLayout();
-      if (item.Checked) {
-        tl.Controls.Add(chartsPanel);
-        await gradientChart.RecalculateAsync(false, false);
-      } else {
-        tl.Controls.Remove(chartsPanel);
-      }
-
-      if (tl.Controls.Count > 0) {
-        SetupYAxis();
-        ReOrderControls();
-        SetStyles();
-      }
-      tl.ResumeLayout();
-      tl.Refresh();
-      densityComboBox_SelectedIndexChanged(this, EventArgs.Empty);
-    }
-
-    private void automaticYAxisCheckBox_CheckedChanged(object sender, EventArgs e) {
-      limitView.ReadOnly = automaticYAxisCheckBox.Checked;
-      SetupYAxis();
-      gradientChartTableLayout.Refresh();
-      densityComboBox_SelectedIndexChanged(this, EventArgs.Empty); // necessary to realign the density plots
-    }
-
-    private void limit_ValueChanged(object sender, EventArgs e) {
-      if (automaticYAxisCheckBox.Checked)
-        return;
-      SetupYAxis();
-      gradientChartTableLayout.Refresh();
-      densityComboBox_SelectedIndexChanged(this, EventArgs.Empty); // necessary to realign the density plots
-    }
-
-    private void densityComboBox_SelectedIndexChanged(object sender, EventArgs e) {
-      if (Content == null)
-        return;
-
-      int si = densityComboBox.SelectedIndex;
-      if (si == 0) {
-        foreach (var densityChart in densityCharts.Values)
-          densityChart.Visible = false;
-      } else {
-        var indices = GetDensityIndices(si).ToList();
-
-        foreach (var entry in densityCharts) {
-          var variableName = entry.Key;
-          var densityChart = entry.Value;
-          if (!VisibleVariables.Contains(variableName) || gradientCharts[variableName].IsZoomed)
-            continue;
-
-          UpdateDensityChart(densityChart, variableName, indices);
-        }
-      }
-    }
-    private IEnumerable<int> GetDensityIndices(int selectedIndex) {
-      var problemData = Content.ProblemData;
-      return
-        selectedIndex == 1 ? problemData.TrainingIndices :
-        selectedIndex == 2 ? problemData.TestIndices :
-        problemData.AllIndices;
-    }
-    private void UpdateDensityChart(DensityChart densityChart, string variable, IList<int> indices = null) {
-      if (densityComboBox.SelectedIndex == 0)
-        return;
-      if (indices == null) {
-        indices = GetDensityIndices(densityComboBox.SelectedIndex).ToList();
-      }
-      if (Content.ProblemData.Dataset.VariableHasType<double>(variable)) {
-        var data = Content.ProblemData.Dataset.GetDoubleValues(variable, indices).ToList();
-        var gradientChart = gradientCharts[variable] as GradientChart;
-        if (gradientChart != null) {
-          var min = gradientChart.FixedXAxisMin;
-          var max = gradientChart.FixedXAxisMax;
-          var buckets = gradientChart.DrawingSteps;
-          if (min.HasValue && max.HasValue) {
-            densityChart.UpdateChart(data, min.Value, max.Value, buckets);
-            densityChart.Width = gradientChart.Width;
-
-            var gcPlotPosition = gradientChart.InnerPlotPosition;
-            densityChart.Left = (int)(gcPlotPosition.X / 100.0 * gradientChart.Width);
-            densityChart.Width = (int)(gcPlotPosition.Width / 100.0 * gradientChart.Width);
-
-            densityChart.Visible = true;
-          }
-          gradientChart.UpdateTitlePosition();
-        }
-      } else if (Content.ProblemData.Dataset.VariableHasType<string>(variable)) {
-        var data = Content.ProblemData.Dataset.GetStringValues(variable).ToList();
-        var gradientChart = gradientCharts[variable] as FactorGradientChart;
-        if (gradientChart != null) {
-          densityChart.UpdateChart(data);
-          densityChart.Width = gradientChart.Width;
-
-          var gcPlotPosition = gradientChart.InnerPlotPosition;
-          densityChart.Left = (int)(gcPlotPosition.X / 100.0 * gradientChart.Width);
-          densityChart.Width = (int)(gcPlotPosition.Width / 100.0 * gradientChart.Width);
-
-          densityChart.Visible = true;
-
-          gradientChart.UpdateTitlePosition();
-        }
-      }
-    }
-
-    private void columnsNumericUpDown_ValueChanged(object sender, EventArgs e) {
-      MaxColumns = (int)columnsNumericUpDown.Value;
-      int columns = Math.Min(VisibleVariables.Count(), MaxColumns);
-      if (columns > 0) {
-        var tl = gradientChartTableLayout;
-        MaxColumns = columns;
-        tl.SuspendLayout();
-        ReOrderControls();
-        SetStyles();
-        tl.ResumeLayout();
-        tl.Refresh();
-        densityComboBox_SelectedIndexChanged(this, EventArgs.Empty);
-      }
-    }
-
-    private async void solution_ModelChanged(object sender, EventArgs e) {
-      foreach (var variable in VisibleVariables) {
-        var gradientChart = gradientCharts[variable];
-        var densityChart = densityCharts[variable];
-        // recalculate and refresh
-        await gradientChart.RecalculateAsync(false, false);
-        gradientChart.Refresh();
-        UpdateDensityChart(densityChart, variable);
-      }
-    }
-  }
-}
