Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis.Views/3.4/GradientChart.Designer.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis.Views/3.4/GradientChart.Designer.cs	(revision 13841)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis.Views/3.4/GradientChart.Designer.cs	(revision 13842)
@@ -64,9 +64,8 @@
       this.chart.Size = new System.Drawing.Size(453, 308);
       this.chart.TabIndex = 0;
-      this.chart.AnnotationPositionChanged += new System.EventHandler(this.chart_AnnotationPositionChanged);
       this.chart.AnnotationPositionChanging += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.AnnotationPositionChangingEventArgs>(this.chart_AnnotationPositionChanging);
       this.chart.FormatNumber += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.FormatNumberEventArgs>(this.chart_FormatNumber);
-      this.chart.DragDrop += new System.Windows.Forms.DragEventHandler(this.GradientChart_DragDrop);
-      this.chart.DragEnter += new System.Windows.Forms.DragEventHandler(this.GradientChart_DragEnter);
+      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);
       // 
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis.Views/3.4/GradientChart.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis.Views/3.4/GradientChart.cs	(revision 13841)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis.Views/3.4/GradientChart.cs	(revision 13842)
@@ -38,6 +38,11 @@
     private ModifiableDataset internalDataset; // holds the x values for each point drawn
 
-    private CancellationTokenSource cancelCurrentRefresh;
-
+    private CancellationTokenSource cancelCurrentRecalculateSource;
+
+    private readonly List<IRegressionSolution> solutions;
+    private readonly Dictionary<IRegressionSolution, Series> seriesCache;
+    private readonly Dictionary<IRegressionSolution, Series> ciSeriesCache;
+
+    #region Properties
     public bool ShowLegend {
       get { return chart.Legends[0].Enabled; }
@@ -60,10 +65,49 @@
     public int XAxisTicks {
       get { return xAxisTicks; }
-      set { if (xAxisTicks != value) { xAxisTicks = value; UpdateChart(); } }
-    }
+      set { xAxisTicks = value; }
+    }
+    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;
+          RecalculateInternalDataset();
+        }
+      }
+    }
+    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;
+          RecalculateInternalDataset();
+        }
+      }
+    }
+
     private int yAxisTicks = 5;
-    public int YXAxisTicks {
+    public int YAxisTicks {
       get { return yAxisTicks; }
-      set { if (yAxisTicks != value) { yAxisTicks = value; UpdateChart(); } }
+      set { yAxisTicks = value; }
+    }
+    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;
+        }
+      }
+    }
+    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;
+        }
+      }
     }
 
@@ -71,10 +115,10 @@
     public double TrainingMin {
       get { return trainingMin; }
-      set { if (!value.IsAlmost(trainingMin)) { trainingMin = value; UpdateChart(); } }
+      set { trainingMin = value; }
     }
     private double trainingMax = double.MaxValue;
     public double TrainingMax {
       get { return trainingMax; }
-      set { if (!value.IsAlmost(trainingMax)) { trainingMax = value; UpdateChart(); } }
+      set { trainingMax = value; }
     }
 
@@ -82,5 +126,11 @@
     public int DrawingSteps {
       get { return drawingSteps; }
-      set { if (value != drawingSteps) { drawingSteps = value; UpdateChart(); } }
+      set {
+        if (value != drawingSteps) {
+          drawingSteps = value;
+          RecalculateInternalDataset();
+          ResizeAllSeriesData();
+        }
+      }
     }
 
@@ -95,11 +145,5 @@
         freeVariable = value;
         RecalculateInternalDataset();
-        UpdateChart();
-      }
-    }
-
-    private readonly List<IRegressionSolution> solutions = new List<IRegressionSolution>();
-    public IEnumerable<IRegressionSolution> Solutions {
-      get { return solutions; }
+      }
     }
 
@@ -107,7 +151,12 @@
       get { return (VerticalLineAnnotation)chart.Annotations.SingleOrDefault(x => x is VerticalLineAnnotation); }
     }
+    #endregion
 
     public GradientChart() {
       InitializeComponent();
+
+      solutions = new List<IRegressionSolution>();
+      seriesCache = new Dictionary<IRegressionSolution, Series>();
+      ciSeriesCache = new Dictionary<IRegressionSolution, Series>();
 
       // Configure axis
@@ -121,22 +170,21 @@
       chart.ChartAreas[0].CursorY.Interval = 0;
 
-      Disposed +=GradientChart_Disposed;
-    }
-
+      Disposed += GradientChart_Disposed;
+    }
     private void GradientChart_Disposed(object sender, EventArgs e) {
-      if (cancelCurrentRefresh != null) {
-        if (cancelCurrentRefresh.IsCancellationRequested)
-          cancelCurrentRefresh.Cancel();
-        cancelCurrentRefresh.Dispose();
-      }
-    }
-
-    public void Configure(IEnumerable<IRegressionSolution> solutions, ModifiableDataset sharedFixedVariables, string freeVariable, int drawingSteps) {
+      if (cancelCurrentRecalculateSource != null) {
+        if (cancelCurrentRecalculateSource.IsCancellationRequested)
+          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);
-      this.freeVariable = freeVariable;
-      this.drawingSteps = drawingSteps;
 
       // add an event such that whenever a value is changed in the shared dataset, 
@@ -147,19 +195,89 @@
       this.sharedFixedVariables.ItemChanged += sharedFixedVariables_ItemChanged;
 
-      RecalculateTrainingLimits();
+      RecalculateTrainingLimits(initializeAxisRanges);
       RecalculateInternalDataset();
-    }
-
-    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);
+
+      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() {
+      if (IsDisposed
+        || sharedFixedVariables == null || !solutions.Any() || string.IsNullOrEmpty(freeVariable)
+        || trainingMin.IsAlmost(trainingMax) || trainingMin > trainingMax || drawingSteps == 0)
+        return;
+
+      statusLabel.Visible = true;
+      Update(); // immediately show label
+
+      // cancel previous recalculate call
+      if (cancelCurrentRecalculateSource != null)
+        cancelCurrentRecalculateSource.Cancel();
+      cancelCurrentRecalculateSource = new CancellationTokenSource();
+
+      // Set cursor and x-axis
+      var defaultValue = sharedFixedVariables.GetDoubleValue(freeVariable, 0);
+      VerticalLineAnnotation.X = defaultValue;
+      chart.ChartAreas[0].AxisX.Title = FreeVariable + " : " + defaultValue.ToString("N3", CultureInfo.CurrentCulture);
+      SetupAxis(chart.ChartAreas[0].AxisX, trainingMin, trainingMax, XAxisTicks, fixedXAxisMin, fixedXAxisMax);
+
+      // Update series
+      var cancellationToken = cancelCurrentRecalculateSource.Token;
+      try {
+        await UpdateSeriesData(cancellationToken);
+        chart.Update();
+
+        // Set y-axis
+        double ymin = 0, ymax = 0;
+        foreach (var vs in chart.Series.SelectMany(series => series.Points.Select(s => s.YValues))) {
+          for (int i = 0; i < vs.Length; i++) {
+            var v = vs[i];
+            if (ymin > v) ymin = v;
+            if (ymax < v) ymax = v;
+          }
+        }
+        SetupAxis(chart.ChartAreas[0].AxisY, ymin, ymax, YAxisTicks, FixedYAxisMin, FixedYAxisMax);
+        chart.ChartAreas[0].RecalculateAxesScale();
+
+        UpdateOutOfTrainingRangeStripLines();
+
+        statusLabel.Visible = false;
+        Update(); // immediately show
+      }
+      catch (OperationCanceledException) { }
+      catch (AggregateException ae) {
+        if (!ae.InnerExceptions.Any(e => e is OperationCanceledException))
+          throw;
+      }
+    }
+
+    private static 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 = (axisMax - axisMin) / ticks;
+    }
+
+    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;
+      }
     }
 
@@ -168,4 +286,7 @@
       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;
 
@@ -183,138 +304,133 @@
     }
 
-    private void RecalculateTrainingLimits() {
-      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();
-    }
-
-    public async void UpdateChart() {
-      // throw exceptions?
-      if (sharedFixedVariables == null || solutions == null || !solutions.Any())
-        return;
-      if (trainingMin.IsAlmost(trainingMax) || trainingMin > trainingMax || drawingSteps == 0)
-        return;
-      if (IsDisposed)
-        return;
-
-      statusLabel.Visible = true;
-
-      if (cancelCurrentRefresh != null && !cancelCurrentRefresh.IsCancellationRequested)
-        cancelCurrentRefresh.Cancel();
-      cancelCurrentRefresh = new CancellationTokenSource();
-
-      // Set cursor
-      var defaultValue = sharedFixedVariables.GetDoubleValue(freeVariable, 0);
-      VerticalLineAnnotation.X = defaultValue;
-
-      // Calculate X-axis interval
-      double axisMin, axisMax, axisInterval;
-      ChartUtil.CalculateAxisInterval(trainingMin, trainingMax, XAxisTicks, out axisMin, out axisMax, out axisInterval);
-      var axis = chart.ChartAreas[0].AxisX;
-      axis.Minimum = axisMin;
-      axis.Maximum = axisMax;
-      axis.Interval = axisInterval;
-
-      var cancellationToken = cancelCurrentRefresh.Token;
-      // Create series <mean, conf. interval>
-      var seriesDict = new Dictionary<Series, Series>();
-      for (int i = 0; i < solutions.Count; i++) {
-        var solution = solutions[i];
-        try {
-          var series = await CreateSeriesAsync(solution, cancellationToken);
-          if (cancellationToken.IsCancellationRequested)
-            return;
-          series.Item1.Tag = i; // for sorting
-          var meanSeries = series.Item1;
-          var confidenceIntervalSeries = series.Item2;
-          meanSeries.Name = solution.ProblemData.TargetVariable + " " + i;
-          seriesDict.Add(meanSeries, confidenceIntervalSeries);
-          if (confidenceIntervalSeries != null)
-            confidenceIntervalSeries.Name = "95% Conf. Interval " + meanSeries.Name;
-        }
-        catch (TaskCanceledException) {
-          return;
-        }
-      }
-
+    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 series in seriesDict.Keys.OrderBy(s => (int)s.Tag)) {
-        series.LegendText = series.Name;
-        chart.Series.Add(series);
-      }
+      foreach (var solution in solutions) {
+        chart.Series.Add(seriesCache[solution]);
+      }
+
       chart.Palette = ChartColorPalette.BrightPastel;
       chart.ApplyPaletteColors();
       chart.Palette = ChartColorPalette.None;
 
-      foreach (var series in seriesDict.OrderBy(s => (int)s.Key.Tag)) {
-        if (series.Value == null) continue;
-        int idx = chart.Series.IndexOf(series.Key);
-        series.Value.Color = Color.FromArgb(40, series.Key.Color);
-        series.Value.IsVisibleInLegend = false;
-        chart.Series.Insert(idx, series.Value);
-      }
+      // 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);
-
-
-      ////calculate Y-axis interval
-      //double ymin = 0, ymax = 0;
-      //foreach (var vs in chart.Series.SelectMany(series => series.Points.Select(s => s.YValues))) {
-      //  for (int index = 0; index < vs.Length; index++) {
-      //    var v = vs[index];
-      //    if (ymin > v) ymin = v;
-      //    if (ymax < v) ymax = v;
-      //  }
-      //}
-      //ChartUtil.CalculateAxisInterval(ymin, ymax, YXAxisTicks, out axisMin, out axisMax, out axisInterval);
-      //axis = chart.ChartAreas[0].AxisY;
-      //axis.Minimum = axisMin;
-      //axis.Maximum = axisMax;
-      //axis.Interval = axisInterval;
-      //chart.ChartAreas[0].RecalculateAxesScale();
-
-      // set axis title
-      chart.ChartAreas[0].AxisX.Title = FreeVariable + " : " + defaultValue.ToString("N3", CultureInfo.CurrentCulture);
-
-      UpdateStripLines();
-
-      statusLabel.Visible = false;
-    }
-
-    private Task<Tuple<Series, Series>> CreateSeriesAsync(IRegressionSolution solution, CancellationToken cancellationToken) {
+    }
+
+    private Task UpdateSeriesData(CancellationToken cancellationToken) {
       return Task.Run(() => {
-        var xvalues = internalDataset.GetDoubleValues(FreeVariable).ToList();
-        var yvalues = solution.Model.GetEstimatedValues(internalDataset, Enumerable.Range(0, internalDataset.Rows)).ToList();
-
-        var series = new Series { ChartType = SeriesChartType.Line };
-        series.Points.DataBindXY(xvalues, yvalues);
-
-        var confidenceBoundSolution = solution as IConfidenceBoundRegressionSolution;
-        Series confidenceIntervalSeries = null;
-        if (confidenceBoundSolution != null) {
-          var variances = confidenceBoundSolution.Model.GetEstimatedVariances(internalDataset, Enumerable.Range(0, internalDataset.Rows)).ToList();
-
-          var lower = yvalues.Zip(variances, (m, s2) => m - 1.96 * Math.Sqrt(s2)).ToList();
-          var upper = yvalues.Zip(variances, (m, s2) => m + 1.96 * Math.Sqrt(s2)).ToList();
-
-          confidenceIntervalSeries = new Series { ChartType = SeriesChartType.Range, YValuesPerPoint = 2 };
-          confidenceIntervalSeries.Points.DataBindXY(xvalues, lower, upper);
-        }
-        return Tuple.Create(series, confidenceIntervalSeries);
+        Parallel.ForEach(solutions, new ParallelOptions { CancellationToken = cancellationToken }, solution => {
+          var xvalues = internalDataset.GetDoubleValues(FreeVariable).ToList();
+          var yvalues = solution.Model.GetEstimatedValues(internalDataset, Enumerable.Range(0, internalDataset.Rows)).ToList();
+
+          var series = seriesCache[solution];
+          for (int i = 0; i < xvalues.Count; i++)
+            series.Points[i].SetValueXY(xvalues[i], 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);
+            }
+          }
+          cancellationToken.ThrowIfCancellationRequested();
+        });
       }, cancellationToken);
     }
 
-    public void AddSolution(IRegressionSolution solution) {
+    private void ResizeAllSeriesData() {
+      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();
+      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();
+        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;
+      if (solutions.Contains(solution))
+        return;
+
       solutions.Add(solution);
-      RecalculateTrainingLimits();
-      UpdateChart();
-    }
-    public void RemoveSolution(IRegressionSolution solution) {
-      if (!solutions.Remove(solution)) return;
-      RecalculateTrainingLimits();
-      UpdateChart();
+      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();
+    }
+    public async Task RemoveSolutionAsync(IRegressionSolution solution) {
+      if (!solutions.Remove(solution))
+        return;
+
+      RecalculateTrainingLimits(true);
+
+      seriesCache.Remove(solution);
+      ciSeriesCache.Remove(solution);
+
+      await RecalculateAsync();
     }
 
@@ -333,5 +449,5 @@
     }
 
-    private void UpdateStripLines() {
+    private void UpdateOutOfTrainingRangeStripLines() {
       var axisX = chart.ChartAreas[0].AxisX;
       var lowerStripLine = axisX.StripLines[0];
@@ -345,5 +461,5 @@
     }
 
-    #region events
+    #region Events
     public event EventHandler VariableValueChanged;
     public void OnVariableValueChanged(object sender, EventArgs args) {
@@ -353,16 +469,23 @@
     }
 
-    private void chart_AnnotationPositionChanged(object sender, EventArgs e) {
-      //var annotation = VerticalLineAnnotation;
-      //var x = annotation.X;
-      //sharedFixedVariables.SetVariableValue(x, FreeVariable, 0);
-
-      //chart.ChartAreas[0].AxisX.Title = FreeVariable + " : " + x.ToString("N3", CultureInfo.CurrentCulture);
-      //chart.Update();
-
-      //OnVariableValueChanged(this, EventArgs.Empty);
-    }
-
+    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 double oldCurserPosition = double.NaN;
     private void chart_AnnotationPositionChanging(object sender, AnnotationPositionChangingEventArgs e) {
+      if (oldCurserPosition.IsAlmost(e.NewLocationX))
+        return;
+      oldCurserPosition = e.NewLocationX;
+
       var step = (trainingMax - trainingMin) / drawingSteps;
       e.NewLocationX = step * (long)Math.Round(e.NewLocationX / step);
@@ -384,5 +507,6 @@
 
     private void chart_MouseMove(object sender, MouseEventArgs e) {
-      chart.Cursor = chart.HitTest(e.X, e.Y).ChartElementType == ChartElementType.Annotation ? Cursors.VSplit : Cursors.Default;
+      bool hitCursor = chart.HitTest(e.X, e.Y).ChartElementType == ChartElementType.Annotation;
+      chart.Cursor = hitCursor ? Cursors.VSplit : Cursors.Default;
     }
 
@@ -402,13 +526,13 @@
     }
 
-    private void GradientChart_DragDrop(object sender, DragEventArgs e) {
+    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))
-          AddSolution(solution);
-      }
-    }
-    private void GradientChart_DragEnter(object sender, DragEventArgs e) {
+        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;
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis.Views/3.4/RegressionSolutionGradientView.Designer.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis.Views/3.4/RegressionSolutionGradientView.Designer.cs	(revision 13841)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis.Views/3.4/RegressionSolutionGradientView.Designer.cs	(revision 13842)
@@ -89,5 +89,5 @@
       this.gradientChart.TrainingMin = -1.7976931348623157E+308D;
       this.gradientChart.XAxisTicks = 10;
-      this.gradientChart.YXAxisTicks = 5;
+      this.gradientChart.YAxisTicks = 5;
       // 
       // configurationGroupBox
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis.Views/3.4/RegressionSolutionGradientView.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis.Views/3.4/RegressionSolutionGradientView.cs	(revision 13841)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis.Views/3.4/RegressionSolutionGradientView.cs	(revision 13842)
@@ -72,5 +72,5 @@
     }
 
-    private void UpdateConfigurationControls() {
+    private async void UpdateConfigurationControls() {
       variableNames.Clear();
       trackbars.Clear();
@@ -87,7 +87,7 @@
       sharedFixedVariables = new ModifiableDataset(variableNames, newTrackbars.Select(tb => new List<double>(1) { (double)tb.Value }));
       gradientChart.Configure(new[] { Content }, sharedFixedVariables, variableNames.First(), DrawingSteps);
-      gradientChart.UpdateChart();
+      await gradientChart.RecalculateAsync();
 
-      // Add to table and observable lists     
+      // Add to table and observable lists
       tableLayoutPanel.RowCount = variableNames.Count;
       while (tableLayoutPanel.RowStyles.Count < variableNames.Count)
@@ -143,8 +143,13 @@
         tb.Checked = false;
       gradientChart.FreeVariable = variableNames[trackbars.IndexOf(trackBar)];
+      gradientChart.RecalculateAsync();
     }
 
     private void trackbar_LimitsChanged(object sender, EventArgs e) {
-      // Todo adapt bounds
+      var trackBar = sender as DensityTrackbar;
+      if (trackBar == null || !trackBar.Checked) return;
+      gradientChart.FixedXAxisMin = trackBar.Limits.Lower;
+      gradientChart.FixedXAxisMax = trackBar.Limits.Upper;
+      gradientChart.RecalculateAsync();
     }
 
@@ -153,5 +158,5 @@
       if (trackBar == null) return;
       sharedFixedVariables.SetVariableValue((double)trackBar.Value, variableNames[trackbars.IndexOf(trackBar)], 0);
-      gradientChart.UpdateChart();
+      gradientChart.RecalculateAsync();
     }
 
@@ -182,6 +187,4 @@
     }
     #endregion
-
-
   }
 
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis.Views/3.4/RegressionSolutionTargetResponseGradientView.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis.Views/3.4/RegressionSolutionTargetResponseGradientView.cs	(revision 13841)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis.Views/3.4/RegressionSolutionTargetResponseGradientView.cs	(revision 13842)
@@ -76,5 +76,5 @@
           foreach (var chart in gradientChartTableLayout.Controls.Cast<GradientChart>()) {
             if (chart == (GradientChart)o) continue;
-            chart.UpdateChart();
+            chart.RecalculateAsync();
           }
         };
@@ -99,5 +99,5 @@
     }
 
-    private void variableListView_ItemChecked(object sender, ItemCheckedEventArgs e) {
+    private async void variableListView_ItemChecked(object sender, ItemCheckedEventArgs e) {
       if (charts == null) return;
       var item = e.Item;
@@ -111,5 +111,5 @@
       if (item.Checked) {
         tl.Controls.Add(chart);
-        chart.UpdateChart();
+        await chart.RecalculateAsync();
       } else {
         tl.Controls.Remove(chart);
