Index: unk/sources/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/GaussianProcessRegressionSolutionEstimatedValuesView.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/GaussianProcessRegressionSolutionEstimatedValuesView.Designer.cs	(revision 14094)
+++ 	(revision )
@@ -1,62 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2015 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.Algorithms.DataAnalysis.Views {
-  partial class GaussianProcessRegressionSolutionEstimatedValuesView {
-    /// <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.SuspendLayout();
-      // 
-      // EstimatedValuesView
-      // 
-      this.AllowDrop = true;
-      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
-      this.Name = "EstimatedValuesView";
-      this.Size = new System.Drawing.Size(310, 285);
-      this.ResumeLayout(false);
-
-    }
-
-    #endregion
-
-  }
-}
Index: unk/sources/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/GaussianProcessRegressionSolutionEstimatedValuesView.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/GaussianProcessRegressionSolutionEstimatedValuesView.cs	(revision 14094)
+++ 	(revision )
@@ -1,72 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2015 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.Linq;
-using System.Windows.Forms;
-using HeuristicLab.Data;
-using HeuristicLab.MainForm;
-using HeuristicLab.Problems.DataAnalysis.Views;
-
-namespace HeuristicLab.Algorithms.DataAnalysis.Views {
-  [View("Estimated Values")]
-  [Content(typeof(GaussianProcessRegressionSolution), false)]
-  public partial class GaussianProcessRegressionSolutionEstimatedValuesView : RegressionSolutionEstimatedValuesView {
-    private const string ESTIMATEDVARIANCE_TRAINING_SERIES_NAME = "Estimated Variance (training)";
-    private const string ESTIMATEDVARIANCE_TEST_SERIES_NAME = "Estimated Variance (test)";
-
-    public new GaussianProcessRegressionSolution Content {
-      get { return (GaussianProcessRegressionSolution)base.Content; }
-      set { base.Content = value; }
-    }
-
-    public GaussianProcessRegressionSolutionEstimatedValuesView()
-      : base() {
-      InitializeComponent();
-    }
-
-
-    protected override StringMatrix CreateValueMatrix() {
-      var matrix = base.CreateValueMatrix();
-
-      var columnNames = matrix.ColumnNames.Concat(new[] { ESTIMATEDVARIANCE_TRAINING_SERIES_NAME, ESTIMATEDVARIANCE_TEST_SERIES_NAME }).ToList();
-      ((IStringConvertibleMatrix)matrix).Columns += 2;
-      matrix.ColumnNames = columnNames;
-
-      var trainingRows = Content.ProblemData.TrainingIndices;
-      var testRows = Content.ProblemData.TestIndices;
-
-      var estimated_var_training = Content.GetEstimatedVariance(trainingRows).GetEnumerator();
-      var estimated_var_test = Content.GetEstimatedVariance(testRows).GetEnumerator();
-
-      foreach (var row in Content.ProblemData.TrainingIndices) {
-        estimated_var_training.MoveNext();
-        matrix[row, 7] = estimated_var_training.Current.ToString();
-      }
-
-      foreach (var row in Content.ProblemData.TestIndices) {
-        estimated_var_test.MoveNext();
-        matrix[row, 8] = estimated_var_test.Current.ToString();
-      }
-
-
-      return matrix;
-    }
-  }
-}
Index: unk/sources/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/GaussianProcessRegressionSolutionLineChartView.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/GaussianProcessRegressionSolutionLineChartView.Designer.cs	(revision 14094)
+++ 	(revision )
@@ -1,87 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2015 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.Algorithms.DataAnalysis.Views {
-  partial class GaussianProcessRegressionSolutionLineChartView {
-    /// <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() {
-      System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
-      System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
-      this.chart = new HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart();
-      ((System.ComponentModel.ISupportInitialize)(this.chart)).BeginInit();
-      this.SuspendLayout();
-      // 
-      // chart
-      // 
-      chartArea1.Name = "ChartArea";
-      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.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(358, 225);
-      this.chart.TabIndex = 0;
-      this.chart.CustomizeLegend += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.CustomizeLegendEventArgs>(this.chart_CustomizeLegend);
-      this.chart.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.Chart_MouseDoubleClick);
-      this.chart.MouseDown += new System.Windows.Forms.MouseEventHandler(this.chart_MouseDown);
-      this.chart.MouseMove += new System.Windows.Forms.MouseEventHandler(this.chart_MouseMove);
-      // 
-      // RegressionSolutionLineChartView
-      // 
-      this.AllowDrop = true;
-      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
-      this.Controls.Add(this.chart);
-      this.Name = "RegressionSolutionLineChartView";
-      this.Size = new System.Drawing.Size(358, 225);
-      ((System.ComponentModel.ISupportInitialize)(this.chart)).EndInit();
-      this.ResumeLayout(false);
-
-    }
-
-    #endregion
-
-    private HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart chart;
-  }
-}
Index: unk/sources/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/GaussianProcessRegressionSolutionLineChartView.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/GaussianProcessRegressionSolutionLineChartView.cs	(revision 14094)
+++ 	(revision )
@@ -1,336 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2015 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.Generic;
-using System.Drawing;
-using System.Linq;
-using System.Windows.Forms;
-using System.Windows.Forms.DataVisualization.Charting;
-using HeuristicLab.MainForm;
-using HeuristicLab.Problems.DataAnalysis.Views;
-
-namespace HeuristicLab.Algorithms.DataAnalysis.Views {
-  [View("Line Chart (95% confidence interval)")]
-  [Content(typeof(GaussianProcessRegressionSolution))]
-  public partial class GaussianProcessRegressionSolutionLineChartView : DataAnalysisSolutionEvaluationView {
-    private const string TARGETVARIABLE_SERIES_NAME = "Target Variable";
-    private const string ESTIMATEDVALUES_TRAINING_SERIES_NAME = "Estimated Values (training)";
-    private const string ESTIMATEDVALUES_TEST_SERIES_NAME = "Estimated Values (test)";
-    private const string ESTIMATEDVALUES_ALL_SERIES_NAME = "Estimated Values (all samples)";
-
-    public new GaussianProcessRegressionSolution Content {
-      get { return (GaussianProcessRegressionSolution)base.Content; }
-      set { base.Content = value; }
-    }
-
-    public GaussianProcessRegressionSolutionLineChartView()
-      : base() {
-      InitializeComponent();
-      //configure axis
-      this.chart.CustomizeAllChartAreas();
-      this.chart.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
-      this.chart.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
-      this.chart.ChartAreas[0].AxisX.IsStartedFromZero = true;
-      this.chart.ChartAreas[0].CursorX.Interval = 1;
-
-      this.chart.ChartAreas[0].CursorY.IsUserSelectionEnabled = true;
-      this.chart.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
-      this.chart.ChartAreas[0].CursorY.Interval = 0;
-    }
-
-    private void RedrawChart() {
-      this.chart.Series.Clear();
-      if (Content != null) {
-        this.chart.ChartAreas[0].AxisX.Minimum = 0;
-        this.chart.ChartAreas[0].AxisX.Maximum = Content.ProblemData.Dataset.Rows - 1;
-
-        // training series
-        this.chart.Series.Add(ESTIMATEDVALUES_TRAINING_SERIES_NAME);
-        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].LegendText = ESTIMATEDVALUES_TRAINING_SERIES_NAME;
-        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].ChartType = SeriesChartType.Range;
-        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].EmptyPointStyle.Color = this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Color;
-        var mean = Content.EstimatedTrainingValues.ToArray();
-        var s2 = Content.EstimatedTrainingVariance.ToArray();
-        var lower = mean.Zip(s2, GetLowerConfBound).ToArray();
-        var upper = mean.Zip(s2, GetUpperConfBound).ToArray();
-        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Points.DataBindXY(Content.ProblemData.TrainingIndices.ToArray(), lower, upper);
-        this.InsertEmptyPoints(this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME]);
-        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Tag = Content;
-
-        // test series
-        this.chart.Series.Add(ESTIMATEDVALUES_TEST_SERIES_NAME);
-        this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].LegendText = ESTIMATEDVALUES_TEST_SERIES_NAME;
-        this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].ChartType = SeriesChartType.Range;
-
-        mean = Content.EstimatedTestValues.ToArray();
-        s2 = Content.EstimatedTestVariance.ToArray();
-        lower = mean.Zip(s2, GetLowerConfBound).ToArray();
-        upper = mean.Zip(s2, GetUpperConfBound).ToArray();
-        this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].Points.DataBindXY(Content.ProblemData.TestIndices.ToArray(), lower, upper);
-        this.InsertEmptyPoints(this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME]);
-        this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].Tag = Content;
-
-        // series of remaining points
-        int[] allIndices = Enumerable.Range(0, Content.ProblemData.Dataset.Rows).Except(Content.ProblemData.TrainingIndices).Except(Content.ProblemData.TestIndices).ToArray();
-        mean = Content.EstimatedValues.ToArray();
-        s2 = Content.EstimatedVariance.ToArray();
-        lower = mean.Zip(s2, GetLowerConfBound).ToArray();
-        upper = mean.Zip(s2, GetUpperConfBound).ToArray();
-        List<double> allLower = allIndices.Select(index => lower[index]).ToList();
-        List<double> allUpper = allIndices.Select(index => upper[index]).ToList();
-        this.chart.Series.Add(ESTIMATEDVALUES_ALL_SERIES_NAME);
-        this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].LegendText = ESTIMATEDVALUES_ALL_SERIES_NAME;
-        this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].ChartType = SeriesChartType.Range;
-        if (allIndices.Count() > 0) {
-          this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].Points.DataBindXY(allIndices, allLower, allUpper);
-          this.InsertEmptyPoints(this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME]);
-        }
-        this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].Tag = Content;
-
-        // target
-        this.chart.Series.Add(TARGETVARIABLE_SERIES_NAME);
-        this.chart.Series[TARGETVARIABLE_SERIES_NAME].LegendText = Content.ProblemData.TargetVariable;
-        this.chart.Series[TARGETVARIABLE_SERIES_NAME].ChartType = SeriesChartType.FastLine;
-        this.chart.Series[TARGETVARIABLE_SERIES_NAME].Points.DataBindXY(Enumerable.Range(0, Content.ProblemData.Dataset.Rows).ToArray(),
-          Content.ProblemData.Dataset.GetDoubleValues(Content.ProblemData.TargetVariable).ToArray());
-
-        this.ToggleSeriesData(this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME]);
-
-
-        // the series have been added in different order than in the normal line chart 
-        // --> adapt coloring;
-        chart.ApplyPaletteColors();
-        this.chart.Palette = ChartColorPalette.None;
-        var s0Color = chart.Series[0].Color;
-        var s1Color = chart.Series[1].Color;
-        var s2Color = chart.Series[2].Color;
-        var s3Color = chart.Series[3].Color;
-        this.chart.PaletteCustomColors = new Color[] { s1Color, s2Color, s3Color, s0Color };
-
-        UpdateCursorInterval();
-        this.UpdateStripLines();
-      }
-    }
-
-    private void InsertEmptyPoints(Series series) {
-      int i = 0;
-      while (i < series.Points.Count - 1) {
-        if (series.Points[i].IsEmpty) {
-          ++i;
-          continue;
-        }
-
-        var p1 = series.Points[i];
-        var p2 = series.Points[i + 1];
-        // check for consecutive indices
-        if ((int)p2.XValue - (int)p1.XValue != 1) {
-          // insert an empty point between p1 and p2 so that the line will be invisible (transparent)
-          var p = new DataPoint((int)((p1.XValue + p2.XValue) / 2), new double[] { 0.0, 0.0 }) { IsEmpty = true };
-          // insert 
-          series.Points.Insert(i + 1, p);
-        }
-        ++i;
-      }
-    }
-
-    private void UpdateCursorInterval() {
-      var estimatedValues = this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Points.Select(x => x.YValues[0]).DefaultIfEmpty(1.0);
-      var targetValues = this.chart.Series[TARGETVARIABLE_SERIES_NAME].Points.Select(x => x.YValues[0]).DefaultIfEmpty(1.0);
-      double estimatedValuesRange = estimatedValues.Max() - estimatedValues.Min();
-      double targetValuesRange = targetValues.Max() - targetValues.Min();
-      double interestingValuesRange = Math.Min(Math.Max(targetValuesRange, 1.0), Math.Max(estimatedValuesRange, 1.0));
-      double digits = (int)Math.Log10(interestingValuesRange) - 3;
-      double yZoomInterval = Math.Max(Math.Pow(10, digits), 10E-5);
-      this.chart.ChartAreas[0].CursorY.Interval = yZoomInterval;
-    }
-
-    #region events
-    protected override void RegisterContentEvents() {
-      base.RegisterContentEvents();
-      Content.ModelChanged += new EventHandler(Content_ModelChanged);
-      Content.ProblemDataChanged += new EventHandler(Content_ProblemDataChanged);
-    }
-    protected override void DeregisterContentEvents() {
-      base.DeregisterContentEvents();
-      Content.ModelChanged -= new EventHandler(Content_ModelChanged);
-      Content.ProblemDataChanged -= new EventHandler(Content_ProblemDataChanged);
-    }
-
-    protected override void OnContentChanged() {
-      base.OnContentChanged();
-      RedrawChart();
-    }
-    private void Content_ProblemDataChanged(object sender, EventArgs e) {
-      RedrawChart();
-    }
-    private void Content_ModelChanged(object sender, EventArgs e) {
-      RedrawChart();
-    }
-
-
-
-    private void Chart_MouseDoubleClick(object sender, MouseEventArgs e) {
-      HitTestResult result = chart.HitTest(e.X, e.Y);
-      if (result.ChartArea != null && (result.ChartElementType == ChartElementType.PlottingArea ||
-                                       result.ChartElementType == ChartElementType.Gridlines) ||
-                                       result.ChartElementType == ChartElementType.StripLines) {
-        foreach (var axis in result.ChartArea.Axes)
-          axis.ScaleView.ZoomReset(int.MaxValue);
-      }
-    }
-    #endregion
-
-    private void UpdateStripLines() {
-      this.chart.ChartAreas[0].AxisX.StripLines.Clear();
-
-      int[] attr = new int[Content.ProblemData.Dataset.Rows + 1]; // add a virtual last row that is again empty to simplify loop further down
-      foreach (var row in Content.ProblemData.TrainingIndices) {
-        attr[row] += 1;
-      }
-      foreach (var row in Content.ProblemData.TestIndices) {
-        attr[row] += 2;
-      }
-      int start = 0;
-      int curAttr = attr[start];
-      for (int row = 0; row < attr.Length; row++) {
-        if (attr[row] != curAttr) {
-          switch (curAttr) {
-            case 0: break;
-            case 1:
-              this.CreateAndAddStripLine("Training", start, row, Color.FromArgb(40, Color.Green), Color.Transparent);
-              break;
-            case 2:
-              this.CreateAndAddStripLine("Test", start, row, Color.FromArgb(40, Color.Red), Color.Transparent);
-              break;
-            case 3:
-              this.CreateAndAddStripLine("Training and Test", start, row, Color.FromArgb(40, Color.Green), Color.FromArgb(40, Color.Red), ChartHatchStyle.WideUpwardDiagonal);
-              break;
-            default:
-              // should not happen
-              break;
-          }
-          curAttr = attr[row];
-          start = row;
-        }
-      }
-    }
-
-    private void CreateAndAddStripLine(string title, int start, int end, Color color, Color secondColor, ChartHatchStyle hatchStyle = ChartHatchStyle.None) {
-      StripLine stripLine = new StripLine();
-      stripLine.BackColor = color;
-      stripLine.BackSecondaryColor = secondColor;
-      stripLine.BackHatchStyle = hatchStyle;
-      stripLine.Text = title;
-      stripLine.Font = new Font("Times New Roman", 12, FontStyle.Bold);
-      // strip range is [start .. end] inclusive, but we evaluate [start..end[ (end is exclusive)
-      // the strip should be by one longer (starting at start - 0.5 and ending at end + 0.5)
-      stripLine.StripWidth = end - start;
-      stripLine.IntervalOffset = start - 0.5; // start slightly to the left of the first point to clearly indicate the first point in the partition
-      this.chart.ChartAreas[0].AxisX.StripLines.Add(stripLine);
-    }
-
-    private void ToggleSeriesData(Series series) {
-      if (series.Points.Count > 0) {  //checks if series is shown
-        if (this.chart.Series.Any(s => s != series && s.Points.Count > 0)) {
-          ClearPointsQuick(series.Points);
-        }
-      } else if (Content != null) {
-
-        IEnumerable<int> indices = null;
-        IEnumerable<double> mean = null;
-        IEnumerable<double> s2 = null;
-        double[] lower = null;
-        double[] upper = null;
-        switch (series.Name) {
-          case ESTIMATEDVALUES_ALL_SERIES_NAME:
-            indices = Enumerable.Range(0, Content.ProblemData.Dataset.Rows).Except(Content.ProblemData.TrainingIndices).Except(Content.ProblemData.TestIndices).ToArray();
-            mean = Content.EstimatedValues.ToArray();
-            s2 = Content.EstimatedVariance.ToArray();
-            lower = mean.Zip(s2, GetLowerConfBound).ToArray();
-            upper = mean.Zip(s2, GetUpperConfBound).ToArray();
-            lower = indices.Select(index => lower[index]).ToArray();
-            upper = indices.Select(index => upper[index]).ToArray();
-            break;
-          case ESTIMATEDVALUES_TRAINING_SERIES_NAME:
-            indices = Content.ProblemData.TrainingIndices.ToArray();
-            mean = Content.EstimatedTrainingValues.ToArray();
-            s2 = Content.EstimatedTrainingVariance.ToArray();
-            lower = mean.Zip(s2, GetLowerConfBound).ToArray();
-            upper = mean.Zip(s2, GetUpperConfBound).ToArray();
-            break;
-          case ESTIMATEDVALUES_TEST_SERIES_NAME:
-            indices = Content.ProblemData.TestIndices.ToArray();
-            mean = Content.EstimatedTestValues.ToArray();
-            s2 = Content.EstimatedTestVariance.ToArray();
-            lower = mean.Zip(s2, GetLowerConfBound).ToArray();
-            upper = mean.Zip(s2, GetUpperConfBound).ToArray();
-            break;
-        }
-        if (indices.Count() > 0) {
-          series.Points.DataBindXY(indices, lower, upper);
-          this.InsertEmptyPoints(series);
-          chart.Legends[series.Legend].ForeColor = Color.Black;
-          UpdateCursorInterval();
-          chart.Refresh();
-        }
-      }
-    }
-
-    private double GetLowerConfBound(double m, double s) {
-      return m - 1.96 * Math.Sqrt(s);
-    }
-
-
-    private double GetUpperConfBound(double m, double s) {
-      return m + 1.96 * Math.Sqrt(s);
-    }
-
-    // workaround as per http://stackoverflow.com/questions/5744930/datapointcollection-clear-performance
-    private static void ClearPointsQuick(DataPointCollection points) {
-      points.SuspendUpdates();
-      while (points.Count > 0)
-        points.RemoveAt(points.Count - 1);
-      points.ResumeUpdates();
-    }
-
-    private void chart_MouseMove(object sender, MouseEventArgs e) {
-      HitTestResult result = chart.HitTest(e.X, e.Y);
-      if (result.ChartElementType == ChartElementType.LegendItem && result.Series.Name != TARGETVARIABLE_SERIES_NAME)
-        Cursor = Cursors.Hand;
-      else
-        Cursor = Cursors.Default;
-    }
-    private void chart_MouseDown(object sender, MouseEventArgs e) {
-      HitTestResult result = chart.HitTest(e.X, e.Y);
-      if (result.ChartElementType == ChartElementType.LegendItem && result.Series.Name != TARGETVARIABLE_SERIES_NAME) {
-        ToggleSeriesData(result.Series);
-      }
-    }
-
-    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
-      if (chart.Series.Count != 4) return;
-      e.LegendItems[0].Cells[1].ForeColor = this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
-      e.LegendItems[1].Cells[1].ForeColor = this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
-      e.LegendItems[2].Cells[1].ForeColor = this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
-      e.LegendItems[3].Cells[1].ForeColor = this.chart.Series[TARGETVARIABLE_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
-    }
-  }
-}
Index: /trunk/sources/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/HeuristicLab.Algorithms.DataAnalysis.Views-3.4.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/HeuristicLab.Algorithms.DataAnalysis.Views-3.4.csproj	(revision 14094)
+++ /trunk/sources/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/HeuristicLab.Algorithms.DataAnalysis.Views-3.4.csproj	(revision 14095)
@@ -125,10 +125,4 @@
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="GaussianProcessRegressionSolutionEstimatedValuesView.cs">
-      <SubType>UserControl</SubType>
-    </Compile>
-    <Compile Include="GaussianProcessRegressionSolutionEstimatedValuesView.Designer.cs">
-      <DependentUpon>GaussianProcessRegressionSolutionEstimatedValuesView.cs</DependentUpon>
-    </Compile>
     <Compile Include="MeanProdView.cs">
       <SubType>UserControl</SubType>
@@ -180,10 +174,4 @@
     </Compile>
     <Compile Include="Plugin.cs" />
-    <Compile Include="GaussianProcessRegressionSolutionLineChartView.cs">
-      <SubType>UserControl</SubType>
-    </Compile>
-    <Compile Include="GaussianProcessRegressionSolutionLineChartView.Designer.cs">
-      <DependentUpon>GaussianProcessRegressionSolutionLineChartView.cs</DependentUpon>
-    </Compile>
     <Compile Include="SupportVectorMachineModelSupportVectorsView.cs">
       <SubType>UserControl</SubType>
Index: /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessModel.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessModel.cs	(revision 14094)
+++ /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessModel.cs	(revision 14095)
@@ -341,5 +341,5 @@
     }
 
-    public IEnumerable<double> GetEstimatedVariance(IDataset dataset, IEnumerable<int> rows) {
+    public IEnumerable<double> GetEstimatedVariances(IDataset dataset, IEnumerable<int> rows) {
       try {
         if (x == null) {
Index: /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessRegressionSolution.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessRegressionSolution.cs	(revision 14094)
+++ /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessRegressionSolution.cs	(revision 14095)
@@ -20,6 +20,4 @@
 #endregion
 
-using System.Collections.Generic;
-using System.Linq;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -33,6 +31,5 @@
   [Item("GaussianProcessRegressionSolution", "Represents a Gaussian process solution for a regression problem which can be visualized in the GUI.")]
   [StorableClass]
-  public sealed class GaussianProcessRegressionSolution : RegressionSolution, IGaussianProcessSolution {
-    private new readonly Dictionary<int, double> evaluationCache;
+  public sealed class GaussianProcessRegressionSolution : ConfidenceBoundRegressionSolution, IGaussianProcessSolution {
 
     public new IGaussianProcessModel Model {
@@ -44,51 +41,13 @@
     private GaussianProcessRegressionSolution(bool deserializing)
       : base(deserializing) {
-      evaluationCache = new Dictionary<int, double>();
-
     }
     private GaussianProcessRegressionSolution(GaussianProcessRegressionSolution original, Cloner cloner)
-      : base(original, cloner) {
-      evaluationCache = new Dictionary<int, double>(original.evaluationCache);
-    }
+      : base(original, cloner) { }
     public GaussianProcessRegressionSolution(IGaussianProcessModel model, IRegressionProblemData problemData)
-      : base(model, problemData) {
-
-      evaluationCache = new Dictionary<int, double>(problemData.Dataset.Rows);
-    }
+      : base(model, problemData) { }
 
     public override IDeepCloneable Clone(Cloner cloner) {
       return new GaussianProcessRegressionSolution(this, cloner);
     }
-
-    public IEnumerable<double> EstimatedVariance {
-      get { return GetEstimatedVariance(Enumerable.Range(0, ProblemData.Dataset.Rows)); }
-    }
-    public IEnumerable<double> EstimatedTrainingVariance {
-      get { return GetEstimatedVariance(ProblemData.TrainingIndices); }
-    }
-    public IEnumerable<double> EstimatedTestVariance {
-      get { return GetEstimatedVariance(ProblemData.TestIndices); }
-    }
-
-    public IEnumerable<double> GetEstimatedVariance(IEnumerable<int> rows) {
-      var rowsToEvaluate = rows.Except(evaluationCache.Keys);
-      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
-      var valuesEnumerator = Model.GetEstimatedVariance(ProblemData.Dataset, rowsToEvaluate).GetEnumerator();
-
-      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
-        evaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
-      }
-
-      return rows.Select(row => evaluationCache[row]);
-    }
-
-    protected override void OnModelChanged() {
-      evaluationCache.Clear();
-      base.OnModelChanged();
-    }
-    protected override void OnProblemDataChanged() {
-      evaluationCache.Clear();
-      base.OnProblemDataChanged();
-    }
   }
 }
Index: /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/StudentTProcessModel.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/StudentTProcessModel.cs	(revision 14095)
+++ /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/StudentTProcessModel.cs	(revision 14095)
@@ -0,0 +1,406 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a Gaussian process model.
+  /// </summary>
+  [StorableClass]
+  [Item("StudentTProcessModel", "Represents a Student-t process posterior.")]
+  public sealed class StudentTProcessModel : RegressionModel, IGaussianProcessModel {
+    public override IEnumerable<string> VariablesUsedForPrediction {
+      get { return allowedInputVariables; }
+    }
+
+    [Storable]
+    private double negativeLogLikelihood;
+    public double NegativeLogLikelihood {
+      get { return negativeLogLikelihood; }
+    }
+
+    [Storable]
+    private double[] hyperparameterGradients;
+    public double[] HyperparameterGradients {
+      get {
+        var copy = new double[hyperparameterGradients.Length];
+        Array.Copy(hyperparameterGradients, copy, copy.Length);
+        return copy;
+      }
+    }
+
+    [Storable]
+    private ICovarianceFunction covarianceFunction;
+    public ICovarianceFunction CovarianceFunction {
+      get { return covarianceFunction; }
+    }
+    [Storable]
+    private IMeanFunction meanFunction;
+    public IMeanFunction MeanFunction {
+      get { return meanFunction; }
+    }
+
+    [Storable]
+    private string[] allowedInputVariables;
+    public string[] AllowedInputVariables {
+      get { return allowedInputVariables; }
+    }
+
+    [Storable]
+    private double[] alpha;
+    [Storable]
+    private double beta;
+
+    public double SigmaNoise {
+      get { return 0; }
+    }
+
+    [Storable]
+    private double[] meanParameter;
+    [Storable]
+    private double[] covarianceParameter;
+    [Storable]
+    private double nu;
+
+    private double[,] l; // used to be storable in previous versions (is calculated lazily now)
+    private double[,] x; // scaled training dataset, used to be storable in previous versions (is calculated lazily now)
+
+    // BackwardsCompatibility3.4
+    #region Backwards compatible code, remove with 3.5
+    [Storable(Name = "l")] // restore if available but don't store anymore
+    private double[,] l_storable {
+      set { this.l = value; }
+      get {
+        if (trainingDataset == null) return l; // this model has been created with an old version 
+        else return null; // if the training dataset is available l should not be serialized
+      }
+    }
+    [Storable(Name = "x")] // restore if available but don't store anymore
+    private double[,] x_storable {
+      set { this.x = value; }
+      get {
+        if (trainingDataset == null) return x; // this model has been created with an old version 
+        else return null; // if the training dataset is available x should not be serialized
+      }
+    }
+    #endregion
+
+
+    [Storable]
+    private IDataset trainingDataset; // it is better to store the original training dataset completely because this is more efficient in persistence
+    [Storable]
+    private int[] trainingRows;
+
+    [Storable]
+    private Scaling inputScaling;
+
+
+    [StorableConstructor]
+    private StudentTProcessModel(bool deserializing) : base(deserializing) { }
+    private StudentTProcessModel(StudentTProcessModel original, Cloner cloner)
+      : base(original, cloner) {
+      this.meanFunction = cloner.Clone(original.meanFunction);
+      this.covarianceFunction = cloner.Clone(original.covarianceFunction);
+      if (original.inputScaling != null)
+        this.inputScaling = cloner.Clone(original.inputScaling);
+      this.trainingDataset = cloner.Clone(original.trainingDataset);
+      this.negativeLogLikelihood = original.negativeLogLikelihood;
+      if (original.meanParameter != null) {
+        this.meanParameter = (double[])original.meanParameter.Clone();
+      }
+      if (original.covarianceParameter != null) {
+        this.covarianceParameter = (double[])original.covarianceParameter.Clone();
+      }
+      nu = original.nu;
+
+      // shallow copies of arrays because they cannot be modified
+      this.trainingRows = original.trainingRows;
+      this.allowedInputVariables = original.allowedInputVariables;
+      this.alpha = original.alpha;
+      this.beta = original.beta;
+      this.l = original.l;
+      this.x = original.x;
+    }
+    public StudentTProcessModel(IDataset ds, string targetVariable, IEnumerable<string> allowedInputVariables, IEnumerable<int> rows,
+      IEnumerable<double> hyp, IMeanFunction meanFunction, ICovarianceFunction covarianceFunction,
+      bool scaleInputs = true)
+      : base(targetVariable) {
+      this.name = ItemName;
+      this.description = ItemDescription;
+      this.meanFunction = (IMeanFunction)meanFunction.Clone();
+      this.covarianceFunction = (ICovarianceFunction)covarianceFunction.Clone();
+      this.allowedInputVariables = allowedInputVariables.ToArray();
+
+
+      int nVariables = this.allowedInputVariables.Length;
+      meanParameter = hyp
+        .Take(this.meanFunction.GetNumberOfParameters(nVariables))
+        .ToArray();
+
+      covarianceParameter = hyp.Skip(meanParameter.Length)
+                                             .Take(this.covarianceFunction.GetNumberOfParameters(nVariables))
+                                             .ToArray();
+      nu = Math.Exp(hyp.Skip(meanParameter.Length + covarianceParameter.Length).First()) + 2; //TODO check gradient
+      try {
+        CalculateModel(ds, rows, scaleInputs);
+      }
+      catch (alglib.alglibexception ae) {
+        // wrap exception so that calling code doesn't have to know about alglib implementation
+        throw new ArgumentException("There was a problem in the calculation of the Gaussian process model", ae);
+      }
+    }
+
+    private void CalculateModel(IDataset ds, IEnumerable<int> rows, bool scaleInputs = true) {
+      this.trainingDataset = (IDataset)ds.Clone();
+      this.trainingRows = rows.ToArray();
+      this.inputScaling = scaleInputs ? new Scaling(ds, allowedInputVariables, rows) : null;
+
+      x = GetData(ds, this.allowedInputVariables, this.trainingRows, this.inputScaling);
+
+      IEnumerable<double> y;
+      y = ds.GetDoubleValues(TargetVariable, rows);
+
+      int n = x.GetLength(0);
+      var columns = Enumerable.Range(0, x.GetLength(1)).ToArray();
+
+      // calculate cholesky decomposed (lower triangular) covariance matrix
+      var cov = covarianceFunction.GetParameterizedCovarianceFunction(covarianceParameter, columns);
+      this.l = CalculateL(x, cov);
+
+      // calculate mean
+      var mean = meanFunction.GetParameterizedMeanFunction(meanParameter, columns);
+      double[] m = Enumerable.Range(0, x.GetLength(0))
+        .Select(r => mean.Mean(x, r))
+        .ToArray();
+
+      // calculate sum of diagonal elements for likelihood
+      double diagSum = Enumerable.Range(0, n).Select(i => Math.Log(l[i, i])).Sum();
+
+      // solve for alpha
+      double[] ym = y.Zip(m, (a, b) => a - b).ToArray();
+
+      int info;
+      alglib.densesolverreport denseSolveRep;
+
+      alglib.spdmatrixcholeskysolve(l, n, false, ym, out info, out denseSolveRep, out alpha);
+
+      beta = Util.ScalarProd(ym, alpha);
+      double sign0, sign1;
+      double lngamma0 = alglib.lngamma(0.5 * (nu + n), out sign0);
+      lngamma0 *= sign0;
+      double lngamma1 = alglib.lngamma(0.5 * nu, out sign1);
+      lngamma1 *= sign1;
+      negativeLogLikelihood =
+        0.5 * n * Math.Log((nu - 2) * Math.PI) +
+        diagSum +
+        -lngamma0 + lngamma1 +
+        //-Math.Log(alglib.gammafunction((n + nu) / 2) / alglib.gammafunction(nu / 2)) +
+        0.5 * (nu + n) * Math.Log(1 + beta / (nu - 2));
+
+      // derivatives
+      int nAllowedVariables = x.GetLength(1);
+
+      alglib.matinvreport matInvRep;
+      double[,] lCopy = new double[l.GetLength(0), l.GetLength(1)];
+      Array.Copy(l, lCopy, lCopy.Length);
+
+      alglib.spdmatrixcholeskyinverse(ref lCopy, n, false, out info, out matInvRep);
+      double c = (nu + n) / (nu + beta - 2);
+      if (info != 1) throw new ArgumentException("Can't invert matrix to calculate gradients.");
+      for (int i = 0; i < n; i++) {
+        for (int j = 0; j <= i; j++)
+          lCopy[i, j] = lCopy[i, j] - c * alpha[i] * alpha[j];
+      }
+
+      double[] meanGradients = new double[meanFunction.GetNumberOfParameters(nAllowedVariables)];
+      for (int k = 0; k < meanGradients.Length; k++) {
+        var meanGrad = new double[alpha.Length];
+        for (int g = 0; g < meanGrad.Length; g++)
+          meanGrad[g] = mean.Gradient(x, g, k);
+        meanGradients[k] = -Util.ScalarProd(meanGrad, alpha);//TODO not working yet, try to fix with gradient check
+      }
+
+      double[] covGradients = new double[covarianceFunction.GetNumberOfParameters(nAllowedVariables)];
+      if (covGradients.Length > 0) {
+        for (int i = 0; i < n; i++) {
+          for (int j = 0; j < i; j++) {
+            var g = cov.CovarianceGradient(x, i, j);
+            for (int k = 0; k < covGradients.Length; k++) {
+              covGradients[k] += lCopy[i, j] * g[k];
+            }
+          }
+
+          var gDiag = cov.CovarianceGradient(x, i, i);
+          for (int k = 0; k < covGradients.Length; k++) {
+            // diag
+            covGradients[k] += 0.5 * lCopy[i, i] * gDiag[k];
+          }
+        }
+      }
+
+      double nuGradient = 0.5 * n
+        - 0.5 * (nu - 2) * alglib.psi((n + nu) / 2) + 0.5 * (nu - 2) * alglib.psi(nu / 2)
+        + 0.5 * (nu - 2) * Math.Log(1 + beta / (nu - 2)) - beta * (n + nu) / (2 * (beta + (nu - 2)));
+
+      //nuGradient = (nu-2) * nuGradient;
+      hyperparameterGradients =
+        meanGradients
+        .Concat(covGradients)
+        .Concat(new double[] { nuGradient }).ToArray();
+
+    }
+
+    private static double[,] GetData(IDataset ds, IEnumerable<string> allowedInputs, IEnumerable<int> rows, Scaling scaling) {
+      if (scaling != null) {
+        return AlglibUtil.PrepareAndScaleInputMatrix(ds, allowedInputs, rows, scaling);
+      } else {
+        return AlglibUtil.PrepareInputMatrix(ds, allowedInputs, rows);
+      }
+    }
+
+    private static double[,] CalculateL(double[,] x, ParameterizedCovarianceFunction cov) {
+      int n = x.GetLength(0);
+      var l = new double[n, n];
+
+      // calculate covariances
+      for (int i = 0; i < n; i++) {
+        for (int j = i; j < n; j++) {
+          l[j, i] = cov.Covariance(x, i, j);
+        }
+      }
+
+      // cholesky decomposition
+      var res = alglib.trfac.spdmatrixcholesky(ref l, n, false);
+      if (!res) throw new ArgumentException("Matrix is not positive semidefinite");
+      return l;
+    }
+
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new StudentTProcessModel(this, cloner);
+    }
+
+    // is called by the solution creator to set all parameter values of the covariance and mean function
+    // to the optimized values (necessary to make the values visible in the GUI)
+    public void FixParameters() {
+      covarianceFunction.SetParameter(covarianceParameter);
+      meanFunction.SetParameter(meanParameter);
+      covarianceParameter = new double[0];
+      meanParameter = new double[0];
+    }
+
+    #region IRegressionModel Members
+    public override IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows) {
+      return GetEstimatedValuesHelper(dataset, rows);
+    }
+    public override IRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      return new GaussianProcessRegressionSolution(this, new RegressionProblemData(problemData));
+    }
+    #endregion
+
+
+    private IEnumerable<double> GetEstimatedValuesHelper(IDataset dataset, IEnumerable<int> rows) {
+      try {
+        if (x == null) {
+          x = GetData(trainingDataset, allowedInputVariables, trainingRows, inputScaling);
+        }
+        int n = x.GetLength(0);
+
+        double[,] newX = GetData(dataset, allowedInputVariables, rows, inputScaling);
+        int newN = newX.GetLength(0);
+        var columns = Enumerable.Range(0, newX.GetLength(1)).ToArray();
+
+        var Ks = new double[newN][];
+        var mean = meanFunction.GetParameterizedMeanFunction(meanParameter, columns);
+        var ms = Enumerable.Range(0, newX.GetLength(0))
+        .Select(r => mean.Mean(newX, r))
+        .ToArray();
+        var cov = covarianceFunction.GetParameterizedCovarianceFunction(covarianceParameter, columns);
+        for (int i = 0; i < newN; i++) {
+          Ks[i] = new double[n];
+          for (int j = 0; j < n; j++) {
+            Ks[i][j] = cov.CrossCovariance(x, newX, j, i);
+          }
+        }
+
+        return Enumerable.Range(0, newN)
+          .Select(i => ms[i] + Util.ScalarProd(Ks[i], alpha));
+      }
+      catch (alglib.alglibexception ae) {
+        // wrap exception so that calling code doesn't have to know about alglib implementation
+        throw new ArgumentException("There was a problem in the calculation of the Gaussian process model", ae);
+      }
+    }
+
+    public IEnumerable<double> GetEstimatedVariances(IDataset dataset, IEnumerable<int> rows) {
+      try {
+        if (x == null) {
+          x = GetData(trainingDataset, allowedInputVariables, trainingRows, inputScaling);
+        }
+        int n = x.GetLength(0);
+
+        var newX = GetData(dataset, allowedInputVariables, rows, inputScaling);
+        int newN = newX.GetLength(0);
+
+        var kss = new double[newN];
+        double[,] sWKs = new double[n, newN];
+        var cov = covarianceFunction.GetParameterizedCovarianceFunction(covarianceParameter, Enumerable.Range(0, x.GetLength(1)).ToArray());
+
+        if (l == null) {
+          l = CalculateL(x, cov);
+        }
+
+        // for stddev 
+        for (int i = 0; i < newN; i++)
+          kss[i] = cov.Covariance(newX, i, i);
+
+        for (int i = 0; i < newN; i++) {
+          for (int j = 0; j < n; j++) {
+            sWKs[j, i] = cov.CrossCovariance(x, newX, j, i);
+          }
+        }
+
+        // for stddev 
+        alglib.ablas.rmatrixlefttrsm(n, newN, l, 0, 0, false, false, 0, ref sWKs, 0, 0);
+
+        for (int i = 0; i < newN; i++) {
+          var col = Util.GetCol(sWKs, i).ToArray();
+          var sumV = Util.ScalarProd(col, col);
+          kss[i] -= sumV;
+          kss[i] *= (nu + beta - 2) / (nu + n - 2);
+          if (kss[i] < 0) kss[i] = 0;
+        }
+        return kss;
+      }
+      catch (alglib.alglibexception ae) {
+        // wrap exception so that calling code doesn't have to know about alglib implementation
+        throw new ArgumentException("There was a problem in the calculation of the Gaussian process model", ae);
+      }
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/RegressionTreeBuilder.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/RegressionTreeBuilder.cs	(revision 14094)
+++ /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/RegressionTreeBuilder.cs	(revision 14095)
@@ -22,5 +22,4 @@
 
 using System;
-using System.Collections;
 using System.Collections.Generic;
 using System.Diagnostics;
@@ -129,6 +128,6 @@
 
       // y and curPred are changed in gradient boosting
-      this.y = y; 
-      this.curPred = curPred; 
+      this.y = y;
+      this.curPred = curPred;
 
       // shuffle row idx
Index: /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IGaussianProcessModel.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IGaussianProcessModel.cs	(revision 14094)
+++ /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IGaussianProcessModel.cs	(revision 14095)
@@ -20,5 +20,4 @@
 #endregion
 
-using System.Collections.Generic;
 using HeuristicLab.Problems.DataAnalysis;
 
@@ -27,5 +26,5 @@
   /// Interface to represent a Gaussian process posterior
   /// </summary>
-  public interface IGaussianProcessModel : IRegressionModel {
+  public interface IGaussianProcessModel : IConfidenceBoundRegressionModel {
     double NegativeLogLikelihood { get; }
     double SigmaNoise { get; }
@@ -34,5 +33,4 @@
     double[] HyperparameterGradients { get; }
 
-    IEnumerable<double> GetEstimatedVariance(IDataset ds, IEnumerable<int> rows);
     void FixParameters();
   }
Index: /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IGaussianProcessSolution.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IGaussianProcessSolution.cs	(revision 14094)
+++ /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IGaussianProcessSolution.cs	(revision 14095)
@@ -26,5 +26,5 @@
   /// Interface to represent a Gaussian process solution (either regression or classification)
   /// </summary>
-  public interface IGaussianProcessSolution : IDataAnalysisSolution {
+  public interface IGaussianProcessSolution : IConfidenceBoundRegressionSolution {
     new IGaussianProcessModel Model { get; }
   }
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/DensityChart.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/DensityChart.Designer.cs	(revision 14095)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/DensityChart.Designer.cs	(revision 14095)
@@ -0,0 +1,98 @@
+﻿#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 DensityChart {
+    /// <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.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
+      System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series();
+      this.chart = new HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart();
+      ((System.ComponentModel.ISupportInitialize)(this.chart)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // Chart
+      // 
+      this.chart.BackColor = System.Drawing.Color.Transparent;
+      chartArea1.AxisX.Enabled = System.Windows.Forms.DataVisualization.Charting.AxisEnabled.False;
+      chartArea1.AxisX.IsMarginVisible = false;
+      chartArea1.AxisY.Enabled = System.Windows.Forms.DataVisualization.Charting.AxisEnabled.False;
+      chartArea1.AxisY.IsMarginVisible = false;
+      chartArea1.AxisY.Minimum = 0D;
+      chartArea1.BorderColor = System.Drawing.Color.Empty;
+      chartArea1.Name = "ChartArea";
+      chartArea1.Position.Auto = false;
+      chartArea1.Position.Height = 100F;
+      chartArea1.Position.Width = 100F;
+      this.chart.ChartAreas.Add(chartArea1);
+      this.chart.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.chart.EnableDoubleClickResetsZoom = false;
+      this.chart.EnableMiddleClickPanning = false;
+      this.chart.Location = new System.Drawing.Point(0, 0);
+      this.chart.Name = "chart";
+      series1.ChartArea = "ChartArea";
+      series1.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.StepLine;
+      series1.Name = "Series1";
+      this.chart.Series.Add(series1);
+      this.chart.Size = new System.Drawing.Size(449, 71);
+      this.chart.TabIndex = 0;
+      this.chart.Text = "Density";
+      // 
+      // DensityChart
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.BackColor = System.Drawing.Color.Transparent;
+      this.Controls.Add(this.chart);
+      this.Name = "DensityChart";
+      this.Size = new System.Drawing.Size(449, 71);
+      ((System.ComponentModel.ISupportInitialize)(this.chart)).EndInit();
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    private Visualization.ChartControlsExtensions.EnhancedChart chart;
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/DensityChart.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/DensityChart.cs	(revision 14095)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/DensityChart.cs	(revision 14095)
@@ -0,0 +1,72 @@
+﻿#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.Collections.Generic;
+using System.Linq;
+using System.Windows.Forms;
+
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  public partial class DensityChart : UserControl {
+    public DensityChart() {
+      InitializeComponent();
+    }
+
+    public void UpdateChart(IList<double> data, double min, double max, int numBuckets, double minimumHeight = 0.1) {
+      if (data == null || numBuckets < 0 || min > max || max < min)
+        return;
+
+      var buckets = CalculateBuckets(data, numBuckets, min, max);
+
+      // set minimum height of all non-zero buckets on 10% of maximum
+      double minHeight = buckets.Max() * 0.1;
+      for (int i = 0; i < buckets.Length; i++) {
+        if (buckets[i] >= 1 && buckets[i] < minHeight)
+          buckets[i] = minHeight;
+      }
+
+      var points = chart.Series[0].Points;
+      if (points.Count == buckets.Length) {
+        for (int i = 0; i < buckets.Length; i++)
+          points[i].SetValueY(buckets[i]);
+        chart.ChartAreas[0].RecalculateAxesScale();
+        chart.Refresh();
+      } else {
+        chart.Series[0].Points.DataBindY(buckets);
+      }
+    }
+
+    private double[] CalculateBuckets(IList<double> data, int numBuckets, double min, double max) {
+      var buckets = new double[numBuckets];
+      var bucketSize = (max - min) / numBuckets;
+      if (bucketSize > 0.0) {
+        for (int i = 0; i < data.Count; i++) {
+          int bucketIndex = (int)((data[i] - min) / bucketSize);
+          if (bucketIndex == numBuckets) {
+            bucketIndex--;
+          }
+          if (bucketIndex >= 0 && bucketIndex < buckets.Length)
+            buckets[bucketIndex] += 1.0;
+        }
+      }
+      return buckets;
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/DensityTrackbar.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/DensityTrackbar.Designer.cs	(revision 14095)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/DensityTrackbar.Designer.cs	(revision 14095)
@@ -0,0 +1,160 @@
+﻿#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.Algorithms.DataAnalysis.Views {
+  partial class DensityTrackbar {
+    /// <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.radioButton = new System.Windows.Forms.RadioButton();
+      this.trackBar = new System.Windows.Forms.TrackBar();
+      this.chart = new HeuristicLab.Problems.DataAnalysis.Views.DensityChart();
+      this.textBox = new System.Windows.Forms.TextBox();
+      this.groupBox = new System.Windows.Forms.GroupBox();
+      this.doubleLimitView = new HeuristicLab.Problems.DataAnalysis.Views.DoubleLimitView();
+      this.errorProvider = new System.Windows.Forms.ErrorProvider(this.components);
+      ((System.ComponentModel.ISupportInitialize)(this.trackBar)).BeginInit();
+      this.groupBox.SuspendLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // radioButton
+      // 
+      this.radioButton.Location = new System.Drawing.Point(6, 11);
+      this.radioButton.Name = "radioButton";
+      this.radioButton.Size = new System.Drawing.Size(132, 17);
+      this.radioButton.TabIndex = 0;
+      this.radioButton.TabStop = true;
+      this.radioButton.Text = "<Name>";
+      this.radioButton.UseVisualStyleBackColor = true;
+      this.radioButton.CheckedChanged += new System.EventHandler(this.radioButton_CheckedChanged);
+      // 
+      // trackBar
+      // 
+      this.trackBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.trackBar.BackColor = System.Drawing.Color.White;
+      this.trackBar.LargeChange = 100;
+      this.trackBar.Location = new System.Drawing.Point(144, 10);
+      this.trackBar.Maximum = 1000;
+      this.trackBar.Name = "trackBar";
+      this.trackBar.RightToLeft = System.Windows.Forms.RightToLeft.No;
+      this.trackBar.Size = new System.Drawing.Size(371, 45);
+      this.trackBar.TabIndex = 1;
+      this.trackBar.TickFrequency = 100;
+      this.trackBar.Value = 500;
+      this.trackBar.ValueChanged += new System.EventHandler(this.trackBar_ValueChanged);
+      // 
+      // chart
+      // 
+      this.chart.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.chart.Location = new System.Drawing.Point(156, 35);
+      this.chart.Name = "chart";
+      this.chart.Size = new System.Drawing.Size(345, 20);
+      this.chart.TabIndex = 3;
+      // 
+      // textBox
+      // 
+      this.textBox.Location = new System.Drawing.Point(6, 35);
+      this.textBox.Name = "textBox";
+      this.textBox.Size = new System.Drawing.Size(132, 20);
+      this.textBox.TabIndex = 4;
+      this.textBox.Validating += new System.ComponentModel.CancelEventHandler(this.textBox_Validating);
+      this.textBox.Validated += new System.EventHandler(this.textBox_Validated);
+      // 
+      // groupBox
+      // 
+      this.groupBox.Controls.Add(this.radioButton);
+      this.groupBox.Controls.Add(this.doubleLimitView);
+      this.groupBox.Controls.Add(this.chart);
+      this.groupBox.Controls.Add(this.trackBar);
+      this.groupBox.Controls.Add(this.textBox);
+      this.groupBox.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.groupBox.Location = new System.Drawing.Point(0, 0);
+      this.groupBox.Name = "groupBox";
+      this.groupBox.Size = new System.Drawing.Size(678, 62);
+      this.groupBox.TabIndex = 5;
+      this.groupBox.TabStop = false;
+      // 
+      // doubleLimitView
+      // 
+      this.doubleLimitView.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+      this.doubleLimitView.Caption = "DoubleLimit View";
+      this.doubleLimitView.Content = null;
+      this.doubleLimitView.Location = new System.Drawing.Point(521, 10);
+      this.doubleLimitView.Name = "doubleLimitView";
+      this.doubleLimitView.ReadOnly = false;
+      this.doubleLimitView.Size = new System.Drawing.Size(151, 47);
+      this.doubleLimitView.TabIndex = 2;
+      // 
+      // errorProvider
+      // 
+      this.errorProvider.BlinkStyle = System.Windows.Forms.ErrorBlinkStyle.NeverBlink;
+      this.errorProvider.ContainerControl = this;
+      // 
+      // DensityTrackbar
+      // 
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
+      this.Controls.Add(this.groupBox);
+      this.Name = "DensityTrackbar";
+      this.Size = new System.Drawing.Size(678, 62);
+      ((System.ComponentModel.ISupportInitialize)(this.trackBar)).EndInit();
+      this.groupBox.ResumeLayout(false);
+      this.groupBox.PerformLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit();
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.RadioButton radioButton;
+    private System.Windows.Forms.TrackBar trackBar;
+    private Problems.DataAnalysis.Views.DoubleLimitView doubleLimitView;
+    private HeuristicLab.Problems.DataAnalysis.Views.DensityChart chart;
+    private System.Windows.Forms.TextBox textBox;
+    private System.Windows.Forms.GroupBox groupBox;
+    private System.Windows.Forms.ErrorProvider errorProvider;
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/DensityTrackbar.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/DensityTrackbar.cs	(revision 14095)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/DensityTrackbar.cs	(revision 14095)
@@ -0,0 +1,146 @@
+﻿#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.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Globalization;
+using System.Windows.Forms;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.Views {
+  public partial class DensityTrackbar : UserControl {
+
+    public decimal Value {
+      get { return TickToValue(trackBar.Value); }
+      set { trackBar.Value = ValueToTick(value); }
+    }
+    public event EventHandler ValueChanged;
+
+    public bool Checked {
+      get { return radioButton.Checked; }
+      set { radioButton.Checked = value; }
+    }
+    public event EventHandler CheckedChanged;
+
+    public DoubleLimit Limits {
+      get { return doubleLimitView.Content; }
+    }
+    public event EventHandler LimitsChanged;
+
+    private IList<double> trainingValues;
+
+    public DensityTrackbar(string name, DoubleLimit limit, IList<double> trainingValues) {
+      InitializeComponent();
+
+      this.trainingValues = trainingValues;
+
+      doubleLimitView.Content = limit;
+      doubleLimitView.Content.ValueChanged += doubleLimit_ValueChanged;
+
+      textBox.Text = Value.ToString(CultureInfo.InvariantCulture);
+      radioButton.Text = name;
+
+      UpdateDensityChart();
+    }
+
+    public void UpdateTrainingValues(IList<double> trainingValues) {
+      this.trainingValues = trainingValues;
+      UpdateDensityChart();
+    }
+
+    private void UpdateDensityChart() {
+      chart.UpdateChart(trainingValues, Limits.Lower, Limits.Upper,
+        numBuckets: trackBar.Maximum - trackBar.Minimum, minimumHeight: 0.1);
+    }
+
+    #region Event Handlers
+    private void trackBar_ValueChanged(object sender, EventArgs e) {
+      textBox.Text = Value.ToString(CultureInfo.CurrentUICulture);
+      textBox.Update();
+      OnValueChanged();
+    }
+    private void doubleLimit_ValueChanged(object sender, EventArgs e) {
+      UpdateDensityChart();
+      OnLimitsChanged();
+      OnValueChanged();
+    }
+    private void radioButton_CheckedChanged(object sender, EventArgs e) {
+      Checked = radioButton.Checked;
+      trackBar.Enabled = !Checked;
+      textBox.Enabled = !Checked;
+      textBox.Text = Checked ? "Plotted" : Value.ToString(CultureInfo.CurrentUICulture);
+      radioButton.BackColor = Checked ? SystemColors.ActiveCaption : SystemColors.Control;
+      OnCheckedChanged();
+    }
+    protected override void OnTextChanged(EventArgs e) {
+      base.OnTextChanged(e);
+      radioButton.Text = Text;
+    }
+
+    private void textBox_Validating(object sender, CancelEventArgs e) {
+      if (Checked) return;
+      decimal number;
+      if (!decimal.TryParse(textBox.Text, NumberStyles.Any, CultureInfo.CurrentUICulture.NumberFormat, out number)) {
+        e.Cancel = true;
+        errorProvider.SetIconAlignment(textBox, ErrorIconAlignment.MiddleLeft);
+        errorProvider.SetIconPadding(textBox, 2);
+        errorProvider.SetError(textBox, "Illegal number format");
+      }
+    }
+
+    private void textBox_Validated(object sender, EventArgs e) {
+      if (Checked) return;
+      errorProvider.SetError(textBox, string.Empty);
+      Value = decimal.Parse(textBox.Text, NumberStyles.Any, CultureInfo.CurrentUICulture.NumberFormat);
+    }
+    #endregion
+
+    protected virtual void OnValueChanged() {
+      if (ValueChanged != null)
+        ValueChanged(this, EventArgs.Empty);
+    }
+    protected virtual void OnCheckedChanged() {
+      if (CheckedChanged != null)
+        CheckedChanged(this, EventArgs.Empty);
+    }
+    protected virtual void OnLimitsChanged() {
+      if (LimitsChanged != null)
+        LimitsChanged(this, EventArgs.Empty);
+    }
+    #region Hepers
+
+    private decimal TickToValue(int tick) {
+      return TickToValue(tick, trackBar.Maximum - trackBar.Minimum, (decimal)Limits.Lower, (decimal)Limits.Upper);
+    }
+    private int ValueToTick(decimal value) {
+      return ValueToTick(value, trackBar.Maximum - trackBar.Minimum, (decimal)Limits.Lower, (decimal)Limits.Upper);
+    }
+    private static decimal TickToValue(int tick, int numberOfTicks, decimal lower, decimal upper) {
+      return lower + (upper - lower) * tick / numberOfTicks;
+    }
+    private static int ValueToTick(decimal value, int numberOfTicks, decimal lower, decimal upper) {
+      return (int)((value - lower) / ((upper - lower) / numberOfTicks));
+    }
+    #endregion
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/GradientChart.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/GradientChart.Designer.cs	(revision 14095)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/GradientChart.Designer.cs	(revision 14095)
@@ -0,0 +1,133 @@
+﻿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.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(GradientChart));
+      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();
+      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 = 100F;
+      chartArea1.Position.Width = 100F;
+      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;
+      this.chart.SelectionRangeChanged += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.CursorEventArgs>(this.chart_SelectionRangeChanged);
+      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);
+      // 
+      // 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: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/GradientChart.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/GradientChart.cs	(revision 14095)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/GradientChart.cs	(revision 14095)
@@ -0,0 +1,671 @@
+﻿#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.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 {
+    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.ChartAreas[0].AxisX.Title = 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 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);
+      }
+
+      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();
+
+      Update(); // immediately show label
+
+      // cancel previous recalculate call
+      if (cancelCurrentRecalculateSource != null)
+        cancelCurrentRecalculateSource.Cancel();
+      cancelCurrentRecalculateSource = new CancellationTokenSource();
+
+      // 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.ChartAreas[0].AxisX.Title = FreeVariable + " : " + defaultValue.ToString("N3", CultureInfo.CurrentCulture);
+
+      // Update series
+      var cancellationToken = cancelCurrentRecalculateSource.Token;
+      try {
+        var limits = await UpdateAllSeriesDataAsync(cancellationToken);
+        //cancellationToken.ThrowIfCancellationRequested();
+
+        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;
+      }
+    }
+
+    private void SetupAxis(Axis axis, double minValue, double maxValue, int ticks, double? fixedAxisMin, double? fixedAxisMax) {
+      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);
+
+      var variables = sharedFixedVariables.DoubleVariables.ToList();
+      internalDataset = new ModifiableDataset(variables,
+        variables.Select(x => x == FreeVariable
+          ? xvalues
+          : Enumerable.Repeat(sharedFixedVariables.GetDoubleValue(x, 0), xvalues.Count).ToList()
+        )
+      );
+    }
+
+    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 IConfidenceBoundRegressionSolution;
+      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];
+        }
+
+        var confidenceBoundSolution = solution as IConfidenceBoundRegressionSolution;
+        if (confidenceBoundSolution != null) {
+          var confidenceIntervalSeries = ciSeriesCache[solution];
+
+          cancellationToken.ThrowIfCancellationRequested();
+          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;
+          }
+        }
+
+        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) {
+      foreach (var solution1 in solutions) {
+        var variables1 = solution1.ProblemData.Dataset.DoubleVariables;
+        foreach (var solution2 in solutions) {
+          if (solution1 == solution2)
+            continue;
+          var variables2 = solution2.ProblemData.Dataset.DoubleVariables;
+          if (!variables1.All(variables2.Contains))
+            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.DoubleVariables.ToList();
+      var rowIndex = e.Value;
+      var columnIndex = e.Value2;
+
+      var variableName = variables[columnIndex];
+      if (variableName == FreeVariable) return;
+      var v = sharedFixedVariables.GetDoubleValue(variableName, rowIndex);
+      var values = new List<double>(Enumerable.Repeat(v, DrawingSteps));
+      internalDataset.ReplaceVariable(variableName, values);
+    }
+
+    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;
+      var annotation = VerticalLineAnnotation;
+      var x = annotation.X;
+      sharedFixedVariables.SetVariableValue(x, FreeVariable, 0);
+
+      if (ShowCursor) {
+        chart.ChartAreas[0].AxisX.Title = FreeVariable + " : " + x.ToString("N3", 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 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))
+          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);
+    }
+    #endregion
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/GradientChartConfigurationDialog.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/GradientChartConfigurationDialog.Designer.cs	(revision 14095)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/GradientChartConfigurationDialog.Designer.cs	(revision 14095)
@@ -0,0 +1,327 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/GradientChartConfigurationDialog.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/GradientChartConfigurationDialog.cs	(revision 14095)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/GradientChartConfigurationDialog.cs	(revision 14095)
@@ -0,0 +1,119 @@
+﻿#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 {
+        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 {
+        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: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj	(revision 14094)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj	(revision 14095)
@@ -120,4 +120,16 @@
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="DensityChart.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="DensityChart.Designer.cs">
+      <DependentUpon>DensityChart.cs</DependentUpon>
+    </Compile>
+    <Compile Include="DensityTrackbar.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="DensityTrackbar.Designer.cs">
+      <DependentUpon>DensityTrackbar.cs</DependentUpon>
+    </Compile>
     <Compile Include="FeatureCorrelation\TimeframeFeatureCorrelationCalculator.cs" />
     <Compile Include="FeatureCorrelation\AbstractFeatureCorrelationCalculator.cs" />
@@ -183,4 +195,16 @@
       <DependentUpon>FeatureCorrelationView.cs</DependentUpon>
     </Compile>
+    <Compile Include="GradientChart.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="GradientChart.Designer.cs">
+      <DependentUpon>GradientChart.cs</DependentUpon>
+    </Compile>
+    <Compile Include="GradientChartConfigurationDialog.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="GradientChartConfigurationDialog.Designer.cs">
+      <DependentUpon>GradientChartConfigurationDialog.cs</DependentUpon>
+    </Compile>
     <Compile Include="Interfaces\IDataPreprocessorStarter.cs" />
     <Compile Include="MenuItems\ShrinkDataAnalysisRunsMenuItem.cs" />
@@ -198,4 +222,16 @@
       <DependentUpon>ProblemDataView.cs</DependentUpon>
     </Compile>
+    <Compile Include="Regression\ConfidenceBoundRegressionSolutionEstimatedValuesView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Regression\ConfidenceBoundRegressionSolutionEstimatedValuesView.Designer.cs">
+      <DependentUpon>ConfidenceBoundRegressionSolutionEstimatedValuesView.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Regression\ConfidenceBoundRegressionSolutionLineChartView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Regression\ConfidenceBoundRegressionSolutionLineChartView.Designer.cs">
+      <DependentUpon>ConfidenceBoundRegressionSolutionLineChartView.cs</DependentUpon>
+    </Compile>
     <Compile Include="Regression\RegressionEnsembleSolutionModelWeightsView.cs">
       <SubType>UserControl</SubType>
@@ -209,4 +245,16 @@
     <Compile Include="Regression\RegressionFeatureCorrelationView.Designer.cs">
       <DependentUpon>RegressionFeatureCorrelationView.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Regression\RegressionSolutionGradientView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <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: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/ConfidenceBoundRegressionSolutionEstimatedValuesView.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/ConfidenceBoundRegressionSolutionEstimatedValuesView.Designer.cs	(revision 14095)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/ConfidenceBoundRegressionSolutionEstimatedValuesView.Designer.cs	(revision 14095)
@@ -0,0 +1,62 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Algorithms.DataAnalysis.Views {
+  partial class ConfidenceBoundRegressionSolutionEstimatedValuesView {
+    /// <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.SuspendLayout();
+      // 
+      // EstimatedValuesView
+      // 
+      this.AllowDrop = true;
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
+      this.Name = "EstimatedValuesView";
+      this.Size = new System.Drawing.Size(310, 285);
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/ConfidenceBoundRegressionSolutionEstimatedValuesView.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/ConfidenceBoundRegressionSolutionEstimatedValuesView.cs	(revision 14095)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/ConfidenceBoundRegressionSolutionEstimatedValuesView.cs	(revision 14095)
@@ -0,0 +1,80 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Linq;
+using System.Windows.Forms;
+using HeuristicLab.Data;
+using HeuristicLab.MainForm;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Problems.DataAnalysis.Views;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.Views {
+  [View("Estimated Values")]
+  [Content(typeof(IConfidenceBoundRegressionSolution), false)]
+  public partial class ConfidenceBoundRegressionSolutionEstimatedValuesView : RegressionSolutionEstimatedValuesView {
+    private const string ESTIMATEDVARIANCES_SERIES_NAME = "Estimated Variances (all)";
+    private const string ESTIMATEDVARIANCES_TRAINING_SERIES_NAME = "Estimated Variances (training)";
+    private const string ESTIMATEDVARIANCES_TEST_SERIES_NAME = "Estimated Variances (test)";
+
+    public new IConfidenceBoundRegressionSolution Content {
+      get { return (IConfidenceBoundRegressionSolution)base.Content; }
+      set { base.Content = value; }
+    }
+
+    public ConfidenceBoundRegressionSolutionEstimatedValuesView()
+      : base() {
+      InitializeComponent();
+    }
+
+
+    protected override StringMatrix CreateValueMatrix() {
+      var matrix = base.CreateValueMatrix();
+
+      var columnNames = matrix.ColumnNames.Concat(new[] { ESTIMATEDVARIANCES_SERIES_NAME, ESTIMATEDVARIANCES_TRAINING_SERIES_NAME, ESTIMATEDVARIANCES_TEST_SERIES_NAME }).ToList();
+      ((IStringConvertibleMatrix)matrix).Columns += 3;
+      matrix.ColumnNames = columnNames;
+
+      var trainingRows = Content.ProblemData.TrainingIndices;
+      var testRows = Content.ProblemData.TestIndices;
+
+      var estimated_var = Content.EstimatedVariances.GetEnumerator();
+      var estimated_var_training = Content.GetEstimatedVariances(trainingRows).GetEnumerator();
+      var estimated_var_test = Content.GetEstimatedVariances(testRows).GetEnumerator();
+
+      foreach (var row in Enumerable.Range(0, Content.ProblemData.Dataset.Rows)) {
+        estimated_var.MoveNext();
+        matrix[row, 7] = estimated_var.Current.ToString();
+      }
+
+      foreach (var row in Content.ProblemData.TrainingIndices) {
+        estimated_var_training.MoveNext();
+        matrix[row, 8] = estimated_var_training.Current.ToString();
+      }
+
+      foreach (var row in Content.ProblemData.TestIndices) {
+        estimated_var_test.MoveNext();
+        matrix[row, 9] = estimated_var_test.Current.ToString();
+      }
+
+
+      return matrix;
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/ConfidenceBoundRegressionSolutionLineChartView.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/ConfidenceBoundRegressionSolutionLineChartView.Designer.cs	(revision 14095)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/ConfidenceBoundRegressionSolutionLineChartView.Designer.cs	(revision 14095)
@@ -0,0 +1,87 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Algorithms.DataAnalysis.Views {
+  partial class ConfidenceBasedRegressionSolutionLineChartView {
+    /// <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() {
+      System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
+      System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
+      this.chart = new HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart();
+      ((System.ComponentModel.ISupportInitialize)(this.chart)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // chart
+      // 
+      chartArea1.Name = "ChartArea";
+      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.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(358, 225);
+      this.chart.TabIndex = 0;
+      this.chart.CustomizeLegend += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.CustomizeLegendEventArgs>(this.chart_CustomizeLegend);
+      this.chart.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.Chart_MouseDoubleClick);
+      this.chart.MouseDown += new System.Windows.Forms.MouseEventHandler(this.chart_MouseDown);
+      this.chart.MouseMove += new System.Windows.Forms.MouseEventHandler(this.chart_MouseMove);
+      // 
+      // RegressionSolutionLineChartView
+      // 
+      this.AllowDrop = true;
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
+      this.Controls.Add(this.chart);
+      this.Name = "RegressionSolutionLineChartView";
+      this.Size = new System.Drawing.Size(358, 225);
+      ((System.ComponentModel.ISupportInitialize)(this.chart)).EndInit();
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    private HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart chart;
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/ConfidenceBoundRegressionSolutionLineChartView.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/ConfidenceBoundRegressionSolutionLineChartView.cs	(revision 14095)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/ConfidenceBoundRegressionSolutionLineChartView.cs	(revision 14095)
@@ -0,0 +1,337 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Windows.Forms;
+using System.Windows.Forms.DataVisualization.Charting;
+using HeuristicLab.MainForm;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Problems.DataAnalysis.Views;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.Views {
+  [View("Line Chart (95% confidence interval)")]
+  [Content(typeof(IConfidenceBoundRegressionSolution))]
+  public partial class ConfidenceBasedRegressionSolutionLineChartView : DataAnalysisSolutionEvaluationView {
+    private const string TARGETVARIABLE_SERIES_NAME = "Target Variable";
+    private const string ESTIMATEDVALUES_TRAINING_SERIES_NAME = "Estimated Values (training)";
+    private const string ESTIMATEDVALUES_TEST_SERIES_NAME = "Estimated Values (test)";
+    private const string ESTIMATEDVALUES_ALL_SERIES_NAME = "Estimated Values (all samples)";
+
+    public new IConfidenceBoundRegressionSolution Content {
+      get { return (IConfidenceBoundRegressionSolution)base.Content; }
+      set { base.Content = value; }
+    }
+
+    public ConfidenceBasedRegressionSolutionLineChartView()
+      : base() {
+      InitializeComponent();
+      //configure axis
+      this.chart.CustomizeAllChartAreas();
+      this.chart.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
+      this.chart.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
+      this.chart.ChartAreas[0].AxisX.IsStartedFromZero = true;
+      this.chart.ChartAreas[0].CursorX.Interval = 1;
+
+      this.chart.ChartAreas[0].CursorY.IsUserSelectionEnabled = true;
+      this.chart.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
+      this.chart.ChartAreas[0].CursorY.Interval = 0;
+    }
+
+    private void RedrawChart() {
+      this.chart.Series.Clear();
+      if (Content != null) {
+        this.chart.ChartAreas[0].AxisX.Minimum = 0;
+        this.chart.ChartAreas[0].AxisX.Maximum = Content.ProblemData.Dataset.Rows - 1;
+
+        // training series
+        this.chart.Series.Add(ESTIMATEDVALUES_TRAINING_SERIES_NAME);
+        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].LegendText = ESTIMATEDVALUES_TRAINING_SERIES_NAME;
+        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].ChartType = SeriesChartType.Range;
+        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].EmptyPointStyle.Color = this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Color;
+        var mean = Content.EstimatedTrainingValues.ToArray();
+        var s2 = Content.EstimatedTrainingVariances.ToArray();
+        var lower = mean.Zip(s2, GetLowerConfBound).ToArray();
+        var upper = mean.Zip(s2, GetUpperConfBound).ToArray();
+        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Points.DataBindXY(Content.ProblemData.TrainingIndices.ToArray(), lower, upper);
+        this.InsertEmptyPoints(this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME]);
+        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Tag = Content;
+
+        // test series
+        this.chart.Series.Add(ESTIMATEDVALUES_TEST_SERIES_NAME);
+        this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].LegendText = ESTIMATEDVALUES_TEST_SERIES_NAME;
+        this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].ChartType = SeriesChartType.Range;
+
+        mean = Content.EstimatedTestValues.ToArray();
+        s2 = Content.EstimatedTestVariances.ToArray();
+        lower = mean.Zip(s2, GetLowerConfBound).ToArray();
+        upper = mean.Zip(s2, GetUpperConfBound).ToArray();
+        this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].Points.DataBindXY(Content.ProblemData.TestIndices.ToArray(), lower, upper);
+        this.InsertEmptyPoints(this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME]);
+        this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].Tag = Content;
+
+        // series of remaining points
+        int[] allIndices = Enumerable.Range(0, Content.ProblemData.Dataset.Rows).Except(Content.ProblemData.TrainingIndices).Except(Content.ProblemData.TestIndices).ToArray();
+        mean = Content.EstimatedValues.ToArray();
+        s2 = Content.EstimatedVariances.ToArray();
+        lower = mean.Zip(s2, GetLowerConfBound).ToArray();
+        upper = mean.Zip(s2, GetUpperConfBound).ToArray();
+        List<double> allLower = allIndices.Select(index => lower[index]).ToList();
+        List<double> allUpper = allIndices.Select(index => upper[index]).ToList();
+        this.chart.Series.Add(ESTIMATEDVALUES_ALL_SERIES_NAME);
+        this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].LegendText = ESTIMATEDVALUES_ALL_SERIES_NAME;
+        this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].ChartType = SeriesChartType.Range;
+        if (allIndices.Count() > 0) {
+          this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].Points.DataBindXY(allIndices, allLower, allUpper);
+          this.InsertEmptyPoints(this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME]);
+        }
+        this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].Tag = Content;
+
+        // target
+        this.chart.Series.Add(TARGETVARIABLE_SERIES_NAME);
+        this.chart.Series[TARGETVARIABLE_SERIES_NAME].LegendText = Content.ProblemData.TargetVariable;
+        this.chart.Series[TARGETVARIABLE_SERIES_NAME].ChartType = SeriesChartType.FastLine;
+        this.chart.Series[TARGETVARIABLE_SERIES_NAME].Points.DataBindXY(Enumerable.Range(0, Content.ProblemData.Dataset.Rows).ToArray(),
+          Content.ProblemData.Dataset.GetDoubleValues(Content.ProblemData.TargetVariable).ToArray());
+
+        this.ToggleSeriesData(this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME]);
+
+
+        // the series have been added in different order than in the normal line chart 
+        // --> adapt coloring;
+        chart.ApplyPaletteColors();
+        this.chart.Palette = ChartColorPalette.None;
+        var s0Color = chart.Series[0].Color;
+        var s1Color = chart.Series[1].Color;
+        var s2Color = chart.Series[2].Color;
+        var s3Color = chart.Series[3].Color;
+        this.chart.PaletteCustomColors = new Color[] { s1Color, s2Color, s3Color, s0Color };
+
+        UpdateCursorInterval();
+        this.UpdateStripLines();
+      }
+    }
+
+    private void InsertEmptyPoints(Series series) {
+      int i = 0;
+      while (i < series.Points.Count - 1) {
+        if (series.Points[i].IsEmpty) {
+          ++i;
+          continue;
+        }
+
+        var p1 = series.Points[i];
+        var p2 = series.Points[i + 1];
+        // check for consecutive indices
+        if ((int)p2.XValue - (int)p1.XValue != 1) {
+          // insert an empty point between p1 and p2 so that the line will be invisible (transparent)
+          var p = new DataPoint((int)((p1.XValue + p2.XValue) / 2), new double[] { 0.0, 0.0 }) { IsEmpty = true };
+          // insert 
+          series.Points.Insert(i + 1, p);
+        }
+        ++i;
+      }
+    }
+
+    private void UpdateCursorInterval() {
+      var estimatedValues = this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Points.Select(x => x.YValues[0]).DefaultIfEmpty(1.0);
+      var targetValues = this.chart.Series[TARGETVARIABLE_SERIES_NAME].Points.Select(x => x.YValues[0]).DefaultIfEmpty(1.0);
+      double estimatedValuesRange = estimatedValues.Max() - estimatedValues.Min();
+      double targetValuesRange = targetValues.Max() - targetValues.Min();
+      double interestingValuesRange = Math.Min(Math.Max(targetValuesRange, 1.0), Math.Max(estimatedValuesRange, 1.0));
+      double digits = (int)Math.Log10(interestingValuesRange) - 3;
+      double yZoomInterval = Math.Max(Math.Pow(10, digits), 10E-5);
+      this.chart.ChartAreas[0].CursorY.Interval = yZoomInterval;
+    }
+
+    #region events
+    protected override void RegisterContentEvents() {
+      base.RegisterContentEvents();
+      Content.ModelChanged += new EventHandler(Content_ModelChanged);
+      Content.ProblemDataChanged += new EventHandler(Content_ProblemDataChanged);
+    }
+    protected override void DeregisterContentEvents() {
+      base.DeregisterContentEvents();
+      Content.ModelChanged -= new EventHandler(Content_ModelChanged);
+      Content.ProblemDataChanged -= new EventHandler(Content_ProblemDataChanged);
+    }
+
+    protected override void OnContentChanged() {
+      base.OnContentChanged();
+      RedrawChart();
+    }
+    private void Content_ProblemDataChanged(object sender, EventArgs e) {
+      RedrawChart();
+    }
+    private void Content_ModelChanged(object sender, EventArgs e) {
+      RedrawChart();
+    }
+
+
+
+    private void Chart_MouseDoubleClick(object sender, MouseEventArgs e) {
+      HitTestResult result = chart.HitTest(e.X, e.Y);
+      if (result.ChartArea != null && (result.ChartElementType == ChartElementType.PlottingArea ||
+                                       result.ChartElementType == ChartElementType.Gridlines) ||
+                                       result.ChartElementType == ChartElementType.StripLines) {
+        foreach (var axis in result.ChartArea.Axes)
+          axis.ScaleView.ZoomReset(int.MaxValue);
+      }
+    }
+    #endregion
+
+    private void UpdateStripLines() {
+      this.chart.ChartAreas[0].AxisX.StripLines.Clear();
+
+      int[] attr = new int[Content.ProblemData.Dataset.Rows + 1]; // add a virtual last row that is again empty to simplify loop further down
+      foreach (var row in Content.ProblemData.TrainingIndices) {
+        attr[row] += 1;
+      }
+      foreach (var row in Content.ProblemData.TestIndices) {
+        attr[row] += 2;
+      }
+      int start = 0;
+      int curAttr = attr[start];
+      for (int row = 0; row < attr.Length; row++) {
+        if (attr[row] != curAttr) {
+          switch (curAttr) {
+            case 0: break;
+            case 1:
+              this.CreateAndAddStripLine("Training", start, row, Color.FromArgb(40, Color.Green), Color.Transparent);
+              break;
+            case 2:
+              this.CreateAndAddStripLine("Test", start, row, Color.FromArgb(40, Color.Red), Color.Transparent);
+              break;
+            case 3:
+              this.CreateAndAddStripLine("Training and Test", start, row, Color.FromArgb(40, Color.Green), Color.FromArgb(40, Color.Red), ChartHatchStyle.WideUpwardDiagonal);
+              break;
+            default:
+              // should not happen
+              break;
+          }
+          curAttr = attr[row];
+          start = row;
+        }
+      }
+    }
+
+    private void CreateAndAddStripLine(string title, int start, int end, Color color, Color secondColor, ChartHatchStyle hatchStyle = ChartHatchStyle.None) {
+      StripLine stripLine = new StripLine();
+      stripLine.BackColor = color;
+      stripLine.BackSecondaryColor = secondColor;
+      stripLine.BackHatchStyle = hatchStyle;
+      stripLine.Text = title;
+      stripLine.Font = new Font("Times New Roman", 12, FontStyle.Bold);
+      // strip range is [start .. end] inclusive, but we evaluate [start..end[ (end is exclusive)
+      // the strip should be by one longer (starting at start - 0.5 and ending at end + 0.5)
+      stripLine.StripWidth = end - start;
+      stripLine.IntervalOffset = start - 0.5; // start slightly to the left of the first point to clearly indicate the first point in the partition
+      this.chart.ChartAreas[0].AxisX.StripLines.Add(stripLine);
+    }
+
+    private void ToggleSeriesData(Series series) {
+      if (series.Points.Count > 0) {  //checks if series is shown
+        if (this.chart.Series.Any(s => s != series && s.Points.Count > 0)) {
+          ClearPointsQuick(series.Points);
+        }
+      } else if (Content != null) {
+
+        IEnumerable<int> indices = null;
+        IEnumerable<double> mean = null;
+        IEnumerable<double> s2 = null;
+        double[] lower = null;
+        double[] upper = null;
+        switch (series.Name) {
+          case ESTIMATEDVALUES_ALL_SERIES_NAME:
+            indices = Enumerable.Range(0, Content.ProblemData.Dataset.Rows).Except(Content.ProblemData.TrainingIndices).Except(Content.ProblemData.TestIndices).ToArray();
+            mean = Content.EstimatedValues.ToArray();
+            s2 = Content.EstimatedVariances.ToArray();
+            lower = mean.Zip(s2, GetLowerConfBound).ToArray();
+            upper = mean.Zip(s2, GetUpperConfBound).ToArray();
+            lower = indices.Select(index => lower[index]).ToArray();
+            upper = indices.Select(index => upper[index]).ToArray();
+            break;
+          case ESTIMATEDVALUES_TRAINING_SERIES_NAME:
+            indices = Content.ProblemData.TrainingIndices.ToArray();
+            mean = Content.EstimatedTrainingValues.ToArray();
+            s2 = Content.EstimatedTrainingVariances.ToArray();
+            lower = mean.Zip(s2, GetLowerConfBound).ToArray();
+            upper = mean.Zip(s2, GetUpperConfBound).ToArray();
+            break;
+          case ESTIMATEDVALUES_TEST_SERIES_NAME:
+            indices = Content.ProblemData.TestIndices.ToArray();
+            mean = Content.EstimatedTestValues.ToArray();
+            s2 = Content.EstimatedTestVariances.ToArray();
+            lower = mean.Zip(s2, GetLowerConfBound).ToArray();
+            upper = mean.Zip(s2, GetUpperConfBound).ToArray();
+            break;
+        }
+        if (indices.Count() > 0) {
+          series.Points.DataBindXY(indices, lower, upper);
+          this.InsertEmptyPoints(series);
+          chart.Legends[series.Legend].ForeColor = Color.Black;
+          UpdateCursorInterval();
+          chart.Refresh();
+        }
+      }
+    }
+
+    private double GetLowerConfBound(double m, double s) {
+      return m - 1.96 * Math.Sqrt(s);
+    }
+
+
+    private double GetUpperConfBound(double m, double s) {
+      return m + 1.96 * Math.Sqrt(s);
+    }
+
+    // workaround as per http://stackoverflow.com/questions/5744930/datapointcollection-clear-performance
+    private static void ClearPointsQuick(DataPointCollection points) {
+      points.SuspendUpdates();
+      while (points.Count > 0)
+        points.RemoveAt(points.Count - 1);
+      points.ResumeUpdates();
+    }
+
+    private void chart_MouseMove(object sender, MouseEventArgs e) {
+      HitTestResult result = chart.HitTest(e.X, e.Y);
+      if (result.ChartElementType == ChartElementType.LegendItem && result.Series.Name != TARGETVARIABLE_SERIES_NAME)
+        Cursor = Cursors.Hand;
+      else
+        Cursor = Cursors.Default;
+    }
+    private void chart_MouseDown(object sender, MouseEventArgs e) {
+      HitTestResult result = chart.HitTest(e.X, e.Y);
+      if (result.ChartElementType == ChartElementType.LegendItem && result.Series.Name != TARGETVARIABLE_SERIES_NAME) {
+        ToggleSeriesData(result.Series);
+      }
+    }
+
+    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
+      if (chart.Series.Count != 4) return;
+      e.LegendItems[0].Cells[1].ForeColor = this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
+      e.LegendItems[1].Cells[1].ForeColor = this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
+      e.LegendItems[2].Cells[1].ForeColor = this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
+      e.LegendItems[3].Cells[1].ForeColor = this.chart.Series[TARGETVARIABLE_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionGradientView.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionGradientView.Designer.cs	(revision 14095)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionGradientView.Designer.cs	(revision 14095)
@@ -0,0 +1,135 @@
+﻿#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.Algorithms.DataAnalysis.Views {
+  partial class RegressionSolutionGradientView {
+    /// <summary> 
+    /// Required designer variableNames.
+    /// </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.splitContainer = new System.Windows.Forms.SplitContainer();
+      this.gradientChart = new HeuristicLab.Problems.DataAnalysis.Views.GradientChart();
+      this.configurationGroupBox = new System.Windows.Forms.GroupBox();
+      this.tableLayoutPanel = new System.Windows.Forms.TableLayoutPanel();
+      ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
+      this.splitContainer.Panel1.SuspendLayout();
+      this.splitContainer.Panel2.SuspendLayout();
+      this.splitContainer.SuspendLayout();
+      this.configurationGroupBox.SuspendLayout();
+      this.SuspendLayout();
+      // 
+      // splitContainer
+      // 
+      this.splitContainer.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.splitContainer.Location = new System.Drawing.Point(0, 0);
+      this.splitContainer.Name = "splitContainer";
+      this.splitContainer.Orientation = System.Windows.Forms.Orientation.Horizontal;
+      // 
+      // splitContainer.Panel1
+      // 
+      this.splitContainer.Panel1.Controls.Add(this.gradientChart);
+      // 
+      // splitContainer.Panel2
+      // 
+      this.splitContainer.Panel2.Controls.Add(this.configurationGroupBox);
+      this.splitContainer.Size = new System.Drawing.Size(715, 591);
+      this.splitContainer.SplitterDistance = 376;
+      this.splitContainer.TabIndex = 1;
+      // 
+      // gradientChart
+      // 
+      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;
+      // 
+      // configurationGroupBox
+      // 
+      this.configurationGroupBox.Controls.Add(this.tableLayoutPanel);
+      this.configurationGroupBox.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.configurationGroupBox.Location = new System.Drawing.Point(0, 0);
+      this.configurationGroupBox.Name = "configurationGroupBox";
+      this.configurationGroupBox.Size = new System.Drawing.Size(715, 211);
+      this.configurationGroupBox.TabIndex = 1;
+      this.configurationGroupBox.TabStop = false;
+      this.configurationGroupBox.Text = "Configuration";
+      // 
+      // tableLayoutPanel
+      // 
+      this.tableLayoutPanel.AutoScroll = true;
+      this.tableLayoutPanel.ColumnCount = 1;
+      this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
+      this.tableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.tableLayoutPanel.Location = new System.Drawing.Point(3, 16);
+      this.tableLayoutPanel.Name = "tableLayoutPanel";
+      this.tableLayoutPanel.RowCount = 1;
+      this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle());
+      this.tableLayoutPanel.Size = new System.Drawing.Size(709, 192);
+      this.tableLayoutPanel.TabIndex = 0;
+      // 
+      // RegressionSolutionGradientView
+      // 
+      this.AllowDrop = true;
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
+      this.Controls.Add(this.splitContainer);
+      this.Name = "RegressionSolutionGradientView";
+      this.Size = new System.Drawing.Size(715, 591);
+      this.splitContainer.Panel1.ResumeLayout(false);
+      this.splitContainer.Panel2.ResumeLayout(false);
+      ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).EndInit();
+      this.splitContainer.ResumeLayout(false);
+      this.configurationGroupBox.ResumeLayout(false);
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+    private System.Windows.Forms.SplitContainer splitContainer;
+    private System.Windows.Forms.GroupBox configurationGroupBox;
+    private System.Windows.Forms.TableLayoutPanel tableLayoutPanel;
+    private Problems.DataAnalysis.Views.GradientChart gradientChart;
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionGradientView.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionGradientView.cs	(revision 14095)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionGradientView.cs	(revision 14095)
@@ -0,0 +1,223 @@
+﻿#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.Generic;
+using System.Linq;
+using System.Windows.Forms;
+using HeuristicLab.Collections;
+using HeuristicLab.Core.Views;
+using HeuristicLab.MainForm;
+using HeuristicLab.MainForm.WindowsForms;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Visualization.ChartControlsExtensions;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.Views {
+  [View("Gradient View")]
+  [Content(typeof(IRegressionSolution))]
+  public partial class RegressionSolutionGradientView : ItemView {
+    private const int DrawingSteps = 1000;
+
+    private readonly List<string> variableNames;
+    private readonly ObservableList<DensityTrackbar> trackbars;
+    private ModifiableDataset sharedFixedVariables;
+
+    private int ActiveDimension {
+      get { return trackbars.FindIndex(tb => tb.Checked); }
+    }
+
+    public new IRegressionSolution Content {
+      get { return (IRegressionSolution)base.Content; }
+      set { base.Content = value; }
+    }
+
+    public RegressionSolutionGradientView()
+      : base() {
+      variableNames = new List<string>();
+
+      trackbars = new ObservableList<DensityTrackbar>();
+      trackbars.ItemsAdded += (sender, args) => {
+        args.Items.Select(i => i.Value).ForEach(RegisterEvents);
+      };
+      trackbars.ItemsRemoved += (sender, args) => {
+        args.Items.Select(i => i.Value).ForEach(DeregisterEvents);
+      };
+      trackbars.CollectionReset += (sender, args) => {
+        args.OldItems.Select(i => i.Value).ForEach(DeregisterEvents);
+        args.Items.Select(i => i.Value).ForEach(RegisterEvents);
+      };
+
+      InitializeComponent();
+
+      // Avoid additional horizontal scrollbar
+      var vertScrollWidth = SystemInformation.VerticalScrollBarWidth;
+      tableLayoutPanel.Padding = new Padding(0, 0, vertScrollWidth, 0);
+    }
+
+    private async void UpdateConfigurationControls() {
+      variableNames.Clear();
+      trackbars.Clear();
+
+      tableLayoutPanel.SuspendRepaint();
+      tableLayoutPanel.SuspendLayout();
+
+      tableLayoutPanel.RowCount = 0;
+      tableLayoutPanel.Controls.Clear();
+
+      if (Content == null) {
+        tableLayoutPanel.ResumeLayout(false);
+        tableLayoutPanel.ResumeRepaint(false);
+        return;
+      }
+
+      variableNames.AddRange(Content.ProblemData.AllowedInputVariables);
+
+      var newTrackbars = CreateConfiguration();
+
+      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();
+
+      // Add to table and observable lists
+      tableLayoutPanel.RowCount = variableNames.Count;
+      while (tableLayoutPanel.RowStyles.Count < variableNames.Count)
+        tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.AutoSize));
+      for (int i = 0; i < newTrackbars.Count; i++) {
+        // events registered automatically
+        trackbars.Add(newTrackbars[i]);
+        tableLayoutPanel.Controls.Add(newTrackbars[i], 0, i);
+      }
+
+      tableLayoutPanel.ResumeLayout(true);
+      tableLayoutPanel.ResumeRepaint(true);
+
+      // Init Y-axis range
+      var problemData = Content.ProblemData;
+      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);
+      gradientChart.FixedYAxisMin = axisMin;
+      gradientChart.FixedYAxisMax = axisMax;
+
+      trackbars.First().Checked = true;
+    }
+
+    private IList<DensityTrackbar> CreateConfiguration() {
+      var ranges = new List<DoubleLimit>();
+      foreach (string variableName in variableNames) {
+        var values = Content.ProblemData.Dataset.GetDoubleValues(variableName, Content.ProblemData.AllIndices);
+        double min, max, interval;
+        ChartUtil.CalculateAxisInterval(values.Min(), values.Max(), 10, out min, out max, out interval);
+        ranges.Add(new DoubleLimit(min, max));
+      }
+
+      var newTrackbars = new List<DensityTrackbar>();
+      for (int i = 0; i < variableNames.Count; i++) {
+        var name = variableNames[i];
+        var trainingData = Content.ProblemData.Dataset.GetDoubleValues(name, Content.ProblemData.TrainingIndices).ToList();
+
+        var dimensionTrackbar = new DensityTrackbar(name, ranges[i], trainingData) {
+          Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
+        };
+        newTrackbars.Add(dimensionTrackbar);
+      }
+
+      return newTrackbars;
+    }
+
+    private void RegisterEvents(DensityTrackbar trackbar) {
+      trackbar.CheckedChanged += trackbar_CheckedChanged;
+      trackbar.ValueChanged += trackbar_ValueChanged;
+      trackbar.LimitsChanged += trackbar_LimitsChanged;
+    }
+    private void DeregisterEvents(DensityTrackbar trackbar) {
+      trackbar.CheckedChanged -= trackbar_CheckedChanged;
+      trackbar.ValueChanged -= trackbar_ValueChanged;
+      trackbar.LimitsChanged -= trackbar_LimitsChanged;
+    }
+
+    private void trackbar_CheckedChanged(object sender, EventArgs e) {
+      var trackBar = sender as DensityTrackbar;
+      if (trackBar == null || !trackBar.Checked) return;
+      // Uncheck all others
+      foreach (var tb in trackbars.Except(new[] { trackBar }))
+        tb.Checked = false;
+      gradientChart.FreeVariable = variableNames[trackbars.IndexOf(trackBar)];
+      gradientChart.RecalculateAsync();
+    }
+
+    private void trackbar_LimitsChanged(object sender, EventArgs e) {
+      var trackBar = sender as DensityTrackbar;
+      if (trackBar == null || !trackBar.Checked) return;
+      gradientChart.FixedXAxisMin = trackBar.Limits.Lower;
+      gradientChart.FixedXAxisMax = trackBar.Limits.Upper;
+      gradientChart.RecalculateAsync();
+    }
+
+    private void trackbar_ValueChanged(object sender, EventArgs e) {
+      var trackBar = sender as DensityTrackbar;
+      if (trackBar == null) return;
+      sharedFixedVariables.SetVariableValue((double)trackBar.Value, variableNames[trackbars.IndexOf(trackBar)], 0);
+      gradientChart.RecalculateAsync();
+    }
+
+    #region Events
+    protected override void RegisterContentEvents() {
+      base.RegisterContentEvents();
+      Content.ModelChanged += Content_ModelChanged;
+      Content.ProblemDataChanged += Content_ProblemDataChanged;
+    }
+
+    protected override void DeregisterContentEvents() {
+      base.DeregisterContentEvents();
+      Content.ModelChanged -= Content_ModelChanged;
+      Content.ProblemDataChanged -= Content_ProblemDataChanged;
+    }
+
+    protected override void OnContentChanged() {
+      base.OnContentChanged();
+      UpdateConfigurationControls();
+    }
+
+    private void Content_ModelChanged(object sender, EventArgs e) {
+      UpdateConfigurationControls();
+    }
+
+    private void Content_ProblemDataChanged(object sender, EventArgs e) {
+      UpdateConfigurationControls();
+    }
+    #endregion
+  }
+
+  internal static class Extensions {
+    public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) {
+      foreach (T item in source)
+        action(item);
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionTargetResponseGradientView.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionTargetResponseGradientView.Designer.cs	(revision 14095)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionTargetResponseGradientView.Designer.cs	(revision 14095)
@@ -0,0 +1,271 @@
+﻿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: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionTargetResponseGradientView.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionTargetResponseGradientView.cs	(revision 14095)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionTargetResponseGradientView.cs	(revision 14095)
@@ -0,0 +1,402 @@
+﻿#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.Generic;
+using System.Drawing;
+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, GradientChart> gradientCharts;
+    private readonly Dictionary<string, DensityChart> densityCharts;
+    private readonly Dictionary<string, Panel> groupingPanels;
+
+    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<GradientChart> 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, GradientChart>();
+      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
+      var allowedInputVariables = Content.ProblemData.AllowedInputVariables;
+      var variableValues = allowedInputVariables.Select(x => new List<double> { problemData.Dataset.GetDoubleValues(x, problemData.TrainingIndices).Median() });
+      var sharedFixedVariables = new ModifiableDataset(allowedInputVariables, variableValues);
+
+      // create controls
+      gradientCharts.Clear();
+      densityCharts.Clear();
+      groupingPanels.Clear();
+      foreach (var variableName in allowedInputVariables) {
+        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
+        };
+        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);
+        };
+
+        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;
+
+      RecalculateAndRelayoutCharts();
+    }
+
+    private async void RecalculateAndRelayoutCharts() {
+      foreach (var variable in VisibleVariables) {
+        var gradientChart = gradientCharts[variable];
+        await gradientChart.RecalculateAsync();
+      }
+      gradientChartTableLayout.SuspendLayout();
+      SetupYAxis();
+      ReOrderControls();
+      SetStyles();
+      gradientChartTableLayout.ResumeLayout();
+      gradientChartTableLayout.Refresh();
+      foreach (var variable in VisibleVariables) {
+        var densityChart = densityCharts[variable];
+        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[] { (GradientChart)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 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;
+      foreach (var v in VisibleVariables) {
+        var chartsPanel = groupingPanels[v];
+        tl.Controls.Add(chartsPanel, column, row);
+
+        var chart = gradientCharts[v];
+        chart.YAxisTitle = column == 0 ? Content.ProblemData.TargetVariable : 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();
+      } 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();
+      }
+      var data = Content.ProblemData.Dataset.GetDoubleValues(variable, indices).ToList();
+      var gradientChart = gradientCharts[variable];
+      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;
+      }
+    }
+
+    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();
+        gradientChart.Refresh();
+        UpdateDensityChart(densityChart, variable);
+      }
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/RegressionSolutionView.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/RegressionSolutionView.cs	(revision 14094)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/RegressionSolutionView.cs	(revision 14095)
@@ -31,5 +31,5 @@
 
 namespace HeuristicLab.Problems.DataAnalysis.Views {
-  [View("RegressionSolution View")]
+  [View("Solution View")]
   [Content(typeof(RegressionSolutionBase), false)]
   public partial class RegressionSolutionView : DataAnalysisSolutionView {
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj	(revision 14094)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj	(revision 14095)
@@ -138,4 +138,5 @@
     <Compile Include="Implementation\ConstantModel.cs" />
     <Compile Include="Implementation\DataAnalysisModel.cs" />
+    <Compile Include="Implementation\Regression\ConfidenceBoundRegressionSolution.cs" />
     <Compile Include="Implementation\Regression\ConstantRegressionModel.cs" />
     <Compile Include="Implementation\Regression\ConstantRegressionSolution.cs" />
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConfidenceBoundRegressionSolution.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConfidenceBoundRegressionSolution.cs	(revision 14095)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConfidenceBoundRegressionSolution.cs	(revision 14095)
@@ -0,0 +1,90 @@
+﻿#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.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents a regression data analysis solution that supports confidence estimates
+  /// </summary>
+  [StorableClass]
+  public class ConfidenceBoundRegressionSolution : RegressionSolution, IConfidenceBoundRegressionSolution {
+    protected readonly Dictionary<int, double> varianceEvaluationCache;
+
+    public new IConfidenceBoundRegressionModel Model {
+      get { return (IConfidenceBoundRegressionModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    [StorableConstructor]
+    protected ConfidenceBoundRegressionSolution(bool deserializing)
+      : base(deserializing) {
+      varianceEvaluationCache = new Dictionary<int, double>();
+    }
+    protected ConfidenceBoundRegressionSolution(ConfidenceBoundRegressionSolution original, Cloner cloner)
+      : base(original, cloner) {
+      varianceEvaluationCache = new Dictionary<int, double>(original.varianceEvaluationCache);
+    }
+    public ConfidenceBoundRegressionSolution(IConfidenceBoundRegressionModel model, IRegressionProblemData problemData)
+      : base(model, problemData) {
+      varianceEvaluationCache = new Dictionary<int, double>(problemData.Dataset.Rows);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ConfidenceBoundRegressionSolution(this, cloner);
+    }
+
+    public IEnumerable<double> EstimatedVariances {
+      get { return GetEstimatedVariances(Enumerable.Range(0, ProblemData.Dataset.Rows)); }
+    }
+    public IEnumerable<double> EstimatedTrainingVariances {
+      get { return GetEstimatedVariances(ProblemData.TrainingIndices); }
+    }
+    public IEnumerable<double> EstimatedTestVariances {
+      get { return GetEstimatedVariances(ProblemData.TestIndices); }
+    }
+
+    public IEnumerable<double> GetEstimatedVariances(IEnumerable<int> rows) {
+      var rowsToEvaluate = rows.Except(varianceEvaluationCache.Keys);
+      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+      var valuesEnumerator = Model.GetEstimatedVariances(ProblemData.Dataset, rowsToEvaluate).GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+        varianceEvaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+      }
+
+      return rows.Select(row => varianceEvaluationCache[row]);
+    }
+
+    protected override void OnProblemDataChanged() {
+      varianceEvaluationCache.Clear();
+      base.OnProblemDataChanged();
+    }
+
+    protected override void OnModelChanged() {
+      varianceEvaluationCache.Clear();
+      base.OnModelChanged();
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionModel.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionModel.cs	(revision 14094)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionModel.cs	(revision 14095)
@@ -27,3 +27,7 @@
     string TargetVariable { get; }
   }
+
+  public interface IConfidenceBoundRegressionModel : IRegressionModel {
+    IEnumerable<double> GetEstimatedVariances(IDataset dataset, IEnumerable<int> rows);
+  }
 }
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionSolution.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionSolution.cs	(revision 14094)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionSolution.cs	(revision 14095)
@@ -44,3 +44,12 @@
     double TestRootMeanSquaredError { get; }
   }
+
+  public interface IConfidenceBoundRegressionSolution : IRegressionSolution {
+    new IConfidenceBoundRegressionModel Model { get; }
+
+    IEnumerable<double> EstimatedVariances { get; }
+    IEnumerable<double> EstimatedTrainingVariances { get; }
+    IEnumerable<double> EstimatedTestVariances { get; }
+    IEnumerable<double> GetEstimatedVariances(IEnumerable<int> rows);
+  }
 }
