Index: branches/PersistenceSpeedUp/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionLineChartView.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionLineChartView.cs	(revision 6206)
+++ branches/PersistenceSpeedUp/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionLineChartView.cs	(revision 6760)
@@ -20,9 +20,9 @@
 #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.Core.Views;
 using HeuristicLab.MainForm;
 using HeuristicLab.MainForm.WindowsForms;
@@ -31,7 +31,9 @@
   [View("Line Chart")]
   [Content(typeof(IRegressionSolution))]
-  public partial class RegressionSolutionLineChartView : ItemView, IRegressionSolutionEvaluationView {
-    private const string TARGETVARIABLE_SERIES_NAME = "TargetVariable";
-    private const string ESTIMATEDVALUES_SERIES_NAME = "EstimatedValues";
+  public partial class RegressionSolutionLineChartView : 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 IRegressionSolution Content {
@@ -47,4 +49,5 @@
       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;
 
@@ -57,21 +60,51 @@
       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;
+
         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.DataBindY(Content.ProblemData.Dataset.GetVariableValues(Content.ProblemData.TargetVariable));
+        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.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.FastLine;
+        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Points.DataBindXY(Content.ProblemData.TrainingIndizes.ToArray(), Content.EstimatedTrainingValues.ToArray());
+        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Tag = Content;
+        this.chart.DataManipulator.InsertEmptyPoints(1, IntervalType.Number, ESTIMATEDVALUES_TRAINING_SERIES_NAME);
+        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].EmptyPointStyle.BorderWidth = 0;
+        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].EmptyPointStyle.MarkerStyle = MarkerStyle.None;
+
+
+        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.FastLine;
+        this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].Points.DataBindXY(Content.ProblemData.TestIndizes.ToArray(), Content.EstimatedTestValues.ToArray());
+        this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].Tag = Content;
+
+
+        int[] allIndizes = Enumerable.Range(0, Content.ProblemData.Dataset.Rows).Except(Content.ProblemData.TrainingIndizes).Except(Content.ProblemData.TestIndizes).ToArray();
+        var estimatedValues = Content.EstimatedValues.ToArray();
+        List<double> allEstimatedValues = allIndizes.Select(index => estimatedValues[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.FastLine;
+        this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].Points.DataBindXY(allIndizes, allEstimatedValues);
+        this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].Tag = Content;
+        this.chart.DataManipulator.InsertEmptyPoints(1, IntervalType.Number, ESTIMATEDVALUES_ALL_SERIES_NAME);
+        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].EmptyPointStyle.BorderWidth = 0;
+        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].EmptyPointStyle.MarkerStyle = MarkerStyle.None;
+        this.ToggleSeriesData(this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME]);
+
+        UpdateCursorInterval();
         this.UpdateStripLines();
-
-        this.chart.Series.Add(ESTIMATEDVALUES_SERIES_NAME);
-        this.chart.Series[ESTIMATEDVALUES_SERIES_NAME].LegendText = Content.ItemName;
-        this.chart.Series[ESTIMATEDVALUES_SERIES_NAME].ChartType = SeriesChartType.FastLine;
-        this.chart.Series[ESTIMATEDVALUES_SERIES_NAME].Points.DataBindY(Content.EstimatedValues.ToArray());
-        this.chart.Series[ESTIMATEDVALUES_SERIES_NAME].Tag = Content;
-        UpdateCursorInterval();
       }
     }
 
     private void UpdateCursorInterval() {
-      var estimatedValues = this.chart.Series[ESTIMATEDVALUES_SERIES_NAME].Points.Select(x => x.YValues[0]).DefaultIfEmpty(1.0);
+      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();
@@ -95,31 +128,16 @@
     }
 
-    private void Content_ProblemDataChanged(object sender, EventArgs e) {
-      RedrawChart();
-    }
-
-    private void Content_ModelChanged(object sender, EventArgs e) {
-      UpdateEstimatedValuesLineChart();
-    }
-
     protected override void OnContentChanged() {
       base.OnContentChanged();
       RedrawChart();
     }
-
-    private void UpdateEstimatedValuesLineChart() {
-      if (InvokeRequired) Invoke((Action)UpdateEstimatedValuesLineChart);
-      else {
-        if (this.chart.Series.Count > 0) {
-          Series s = this.chart.Series.SingleOrDefault(x => x.Tag == Content);
-          if (s != null) {
-            s.Points.DataBindY(Content.EstimatedValues.ToArray());
-            s.LegendText = Content.ItemName;
-            this.UpdateStripLines();
-            UpdateCursorInterval();
-          }
-        }
-      }
-    }
+    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) {
@@ -136,20 +154,103 @@
     private void UpdateStripLines() {
       this.chart.ChartAreas[0].AxisX.StripLines.Clear();
-      this.CreateAndAddStripLine("Training", Color.FromArgb(20, Color.Green),
-        Content.ProblemData.TrainingPartition.Start,
-        Content.ProblemData.TrainingPartition.End);
-      this.CreateAndAddStripLine("Test", Color.FromArgb(20, Color.Red),
-        Content.ProblemData.TestPartition.Start,
-        Content.ProblemData.TestPartition.End);
-    }
-
-    private void CreateAndAddStripLine(string title, Color c, int start, int end) {
+
+      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.TrainingIndizes) {
+        attr[row] += 1;
+      }
+      foreach (var row in Content.ProblemData.TestIndizes) {
+        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 = c;
+      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;
+      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)) {
+          series.Points.Clear();
+        }
+      } else if (Content != null) {
+        string targetVariableName = Content.ProblemData.TargetVariable;
+
+        IEnumerable<int> indizes = null;
+        IEnumerable<double> predictedValues = null;
+        switch (series.Name) {
+          case ESTIMATEDVALUES_ALL_SERIES_NAME:
+            indizes = Enumerable.Range(0, Content.ProblemData.Dataset.Rows).Except(Content.ProblemData.TrainingIndizes).Except(Content.ProblemData.TestIndizes).ToArray();
+            var estimatedValues = Content.EstimatedValues.ToArray();
+            predictedValues = indizes.Select(index => estimatedValues[index]).ToList();
+            break;
+          case ESTIMATEDVALUES_TRAINING_SERIES_NAME:
+            indizes = Content.ProblemData.TrainingIndizes.ToArray();
+            predictedValues = Content.EstimatedTrainingValues.ToArray();
+            break;
+          case ESTIMATEDVALUES_TEST_SERIES_NAME:
+            indizes = Content.ProblemData.TestIndizes.ToArray();
+            predictedValues = Content.EstimatedTestValues.ToArray();
+            break;
+        }
+        series.Points.DataBindXY(indizes, predictedValues);
+        chart.DataManipulator.InsertEmptyPoints(1, IntervalType.Number, series.Name);
+        chart.Legends[series.Legend].ForeColor = Color.Black;
+        UpdateCursorInterval();
+      }
+    }
+
+    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[TARGETVARIABLE_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
+      e.LegendItems[1].Cells[1].ForeColor = this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
+      e.LegendItems[2].Cells[1].ForeColor = this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
+      e.LegendItems[3].Cells[1].ForeColor = this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
     }
   }
