Index: /trunk/sources/HeuristicLab.CEDMA.Charting/BubbleChart.cs
===================================================================
--- /trunk/sources/HeuristicLab.CEDMA.Charting/BubbleChart.cs	(revision 561)
+++ /trunk/sources/HeuristicLab.CEDMA.Charting/BubbleChart.cs	(revision 562)
@@ -26,4 +26,5 @@
 using System.Linq;
 using HeuristicLab.Charting;
+using System.Windows.Forms;
 
 namespace HeuristicLab.CEDMA.Charting {
@@ -36,7 +37,6 @@
     private const int minAlpha = 50;
     private static readonly Color defaultColor = Color.Blue;
-
-    private List<string> dimensions;
-    private Dictionary<string, List<double>> values;
+    private static readonly Color selectionColor = Color.Red;
+
     private double xJitterFactor = 0.0;
     private double yJitterFactor = 0.0;
@@ -49,28 +49,62 @@
     private double maxX = double.NegativeInfinity;
     private double maxY = double.NegativeInfinity;
-
+    private List<Record> records;
+    private ResultList results;
+    private Dictionary<IPrimitive, Record> primitiveToRecordDictionary;
     private Random random = new Random();
-
-    public BubbleChart(PointD lowerLeft, PointD upperRight)
+    private Group points;
+
+    public BubbleChart(ResultList results, PointD lowerLeft, PointD upperRight)
       : base(lowerLeft, upperRight) {
-      dimensions = new List<string>();
-      values = new Dictionary<string, List<double>>();
-    }
-    public BubbleChart(double x1, double y1, double x2, double y2)
-      : this(new PointD(x1, y1), new PointD(x2, y2)) {
-    }
-
-    public void AddDimension(string name) {
-      dimensions.Add(name);
-      values.Add(name, new List<double>());
-    }
-    public void RemoveDimension(string name) {
-      dimensions.Remove(name);
-      values.Remove(name);
-    }
-
-    public void AddDataPoint(string dimension, double value) {
-      values[dimension].Add(value);
-    }
+      records = new List<Record>();
+      primitiveToRecordDictionary = new Dictionary<IPrimitive, Record>();
+      this.results = results;
+      results.OnRecordAdded += new EventHandler<RecordAddedEventArgs>(results_OnRecordAdded);
+    }
+
+    public BubbleChart(ResultList results, double x1, double y1, double x2, double y2)
+      : this(results, new PointD(x1, y1), new PointD(x2, y2)) {
+    }
+
+    void results_OnRecordAdded(object sender, RecordAddedEventArgs e) {
+      lock(records) {
+        e.Record.OnSelectionChanged += new EventHandler(Record_OnSelectionChanged);
+        records.Add(e.Record);
+      }
+    }
+
+    void Record_OnSelectionChanged(object sender, EventArgs e) {
+      Record r = (Record)sender;
+      foreach(KeyValuePair<IPrimitive, Record> pair in primitiveToRecordDictionary) {
+        if(pair.Value == r) {
+          IPrimitive primitive = pair.Key;
+          if(r.Selected) {
+            int alpha = primitive.Pen.Color.A;
+            primitive.Pen.Color = Color.FromArgb(alpha, selectionColor);
+            primitive.Brush = primitive.Pen.Brush;
+            primitive.IntoForeground();
+          } else {
+            int alpha = primitive.Pen.Color.A;
+            primitive.Pen.Color = Color.FromArgb(alpha, defaultColor);
+            primitive.Brush = primitive.Pen.Brush;
+            primitive.IntoBackground();
+          }
+          primitive.EnforceUpdate();
+        }
+      }
+    }
+
+    //public void AddDimension(string name) {
+    //  dimensions.Add(name);
+    //  values.Add(name, new List<double>());
+    //}
+    //public void RemoveDimension(string name) {
+    //  dimensions.Remove(name);
+    //  values.Remove(name);
+    //}
+
+    //public void AddDataPoint(string dimension, double value) {
+    //  values[dimension].Add(value);
+    //}
 
     public void SetBubbleSizeDimension(string dimension, bool inverted) {
@@ -91,12 +125,4 @@
     }
 
-    public override void MouseClick(Point point, System.Windows.Forms.MouseButtons button) {
-      // should select the model in the underlying model
-    }
-
-    public override void MouseDoubleClick(Point point, System.Windows.Forms.MouseButtons button) {
-      // should open the model
-    }
-
     internal void SetJitter(double xJitterFactor, double yJitterFactor) {
       this.xJitterFactor = xJitterFactor * maxXJitterPercent * Size.Width;
@@ -107,48 +133,51 @@
 
     private void Repaint() {
-
-      List<double> xs = values[xDimension];
-      List<double> ys = values[yDimension];
-
-      List<double> sizes = null;
-      double maxSize = 1;
-      double minSize = 1;
-      if(sizeDimension != null && values.ContainsKey(sizeDimension)) {
-        sizes = values[sizeDimension];
-        maxSize = sizes.Max();
-        minSize = sizes.Min();
-      }
-      UpdateEnabled = false;
-      Group.Clear();
-      Group.Add(new Axis(this, 0, 0, AxisType.Both));
-      UpdateViewSize(0, 0, 5);
-      Group points = new Group(this);
-      int n = Math.Min(xs.Count, ys.Count);
-      if(sizes != null) n = Math.Min(n, sizes.Count);
-      for(int i = 0; i < n; i++) {
-        double x = xs[i] + (random.NextDouble() * 2.0 - 1.0) * xJitterFactor;
-        double y = ys[i] + (random.NextDouble() * 2.0 - 1.0) * yJitterFactor;
-        int size;
-        if(sizes != null) {
-          size = CalculateSize(sizes[i], minSize, maxSize);
-        } else {
-          size = minBubbleSize;
-        }
-
-        if(double.IsInfinity(x) || x == double.MaxValue || x == double.MinValue) x = double.NaN;
-        if(double.IsInfinity(y) || y == double.MaxValue || y == double.MinValue) y = double.NaN;
-        if(!double.IsNaN(x) && !double.IsNaN(y)) {
-          UpdateViewSize(x, y, size);
-          int alpha = CalculateAlpha(size);
-          Pen pen = new Pen(Color.FromArgb(alpha, defaultColor));
-          Brush brush = pen.Brush;
-          points.Add(new FixedSizeCircle(this, x, y, size, pen, brush));
-        }
-      }
-      Group.Add(points);
-      UpdateEnabled = true;
+      lock(records) {
+        double maxSize = 1;
+        double minSize = 1;
+        if(sizeDimension != null) {
+          var sizes = records.Select(r => r.Get(sizeDimension));
+          maxSize = sizes.Max();
+          minSize = sizes.Min();
+        }
+        UpdateEnabled = false;
+        Group.Clear();
+        primitiveToRecordDictionary.Clear();
+        points = new Group(this);
+        Group.Add(new Axis(this, 0, 0, AxisType.Both));
+        UpdateViewSize(0, 0, 5);
+        foreach(Record r in records) {
+          double x = r.Get(xDimension) + (random.NextDouble() * 2.0 - 1.0) * xJitterFactor;
+          double y = r.Get(yDimension) + (random.NextDouble() * 2.0 - 1.0) * yJitterFactor;
+          int size = CalculateSize(r.Get(sizeDimension), minSize, maxSize);
+
+          if(double.IsInfinity(x) || x == double.MaxValue || x == double.MinValue) x = double.NaN;
+          if(double.IsInfinity(y) || y == double.MaxValue || y == double.MinValue) y = double.NaN;
+          if(!double.IsNaN(x) && !double.IsNaN(y)) {
+            UpdateViewSize(x, y, size);
+            int alpha = CalculateAlpha(size);
+            Pen pen = new Pen(Color.FromArgb(alpha, defaultColor));
+            Brush brush = pen.Brush;
+            FixedSizeCircle c = new FixedSizeCircle(this, x, y, size, pen, brush);
+            c.ToolTipText = CreateToolTipText(r);
+            points.Add(c);
+            primitiveToRecordDictionary[c] = r;
+          }
+        }
+        Group.Add(points);
+        UpdateEnabled = true;
+      }
+    }
+
+    private string CreateToolTipText(Record r) {
+      StringBuilder b = new StringBuilder();
+      foreach(KeyValuePair<string, double> v in r.Values) {
+        b.Append(v.Key).Append(" = ").Append(v.Value).AppendLine();
+      }
+      return b.ToString();
     }
 
     private int CalculateSize(double size, double minSize, double maxSize) {
+      if(double.IsNaN(size)) return minBubbleSize;
       double sizeDifference = ((size - minSize) / (maxSize - minSize) * (maxBubbleSize - minBubbleSize));
       if(invertSize) return maxBubbleSize - (int)sizeDifference;
@@ -186,4 +215,26 @@
       maxY = double.NegativeInfinity;
     }
+
+    public override void MouseClick(Point point, MouseButtons button) {
+      if(button == MouseButtons.Left) {
+        Record r;
+        IPrimitive p = points.GetPrimitive(TransformPixelToWorld(point));
+        if(p != null) {
+          primitiveToRecordDictionary.TryGetValue(p, out r);
+          if(r != null) r.ToggleSelected();
+        }
+      } else base.MouseClick(point, button);
+    }
+
+    public override void MouseDoubleClick(Point point, MouseButtons button) {
+      if(button == MouseButtons.Left) {
+        Record r;
+        IPrimitive p = points.GetPrimitive(TransformPixelToWorld(point));
+        if(p != null) {
+          primitiveToRecordDictionary.TryGetValue(p, out r);
+          if(r != null) results.OpenModel(r);
+        }
+      } else base.MouseDoubleClick(point, button);
+    }
   }
 }
Index: /trunk/sources/HeuristicLab.CEDMA.Charting/ResultList.cs
===================================================================
--- /trunk/sources/HeuristicLab.CEDMA.Charting/ResultList.cs	(revision 561)
+++ /trunk/sources/HeuristicLab.CEDMA.Charting/ResultList.cs	(revision 562)
@@ -30,6 +30,50 @@
 using System.Runtime.Serialization;
 using System.IO;
+using HeuristicLab.PluginInfrastructure;
 
 namespace HeuristicLab.CEDMA.Charting {
+  public class Record {
+    private Dictionary<string, double> values = new Dictionary<string, double>();
+    public Dictionary<string,double> Values {
+      get {
+        return values;
+      }
+    }
+
+    private bool selected = false;
+    public bool Selected { get { return selected; } }
+
+    private string uri;
+    public string Uri { get { return uri; } }
+    public Record(string uri) {
+      this.uri = uri;
+    }
+
+    public void Set(string name, double value) {
+      Values.Add(name, value);
+    }
+
+    public double Get(string name) {
+      if(name==null || !Values.ContainsKey(name)) return double.NaN;
+      return Values[name];
+    }
+
+    public void ToggleSelected() {
+      selected = !selected;
+      if(OnSelectionChanged != null) OnSelectionChanged(this, new EventArgs());
+    }
+
+    public event EventHandler OnSelectionChanged;
+  }
+
+  public class RecordAddedEventArgs : EventArgs {
+    private Record record;
+    public Record Record { get { return record; } }
+    public RecordAddedEventArgs(Record r)
+      : base() {
+      this.record = r;
+    }
+  }
+
   public class ResultList : ItemBase {
     private const string cedmaNS = "http://www.heuristiclab.com/cedma/";
@@ -54,4 +98,5 @@
     private readonly Entity treeSizePredicate = new Entity(cedmaNS + "TreeSize");
     private readonly Entity treeHeightPredicate = new Entity(cedmaNS + "TreeHeight");
+    private readonly Entity rawDataPredicate = new Entity(cedmaNS + "rawData");
     private readonly Entity anyEntity = new Entity(null);
 
@@ -74,30 +119,10 @@
       }
     }
-    private Dictionary<string, List<double>> allVariables;
+
+    public event EventHandler<RecordAddedEventArgs> OnRecordAdded;
+
+    private List<Record> records;
 
     private void ReloadList() {
-      List<double> trainingMAPE = new List<double>();
-      List<double> validationMAPE = new List<double>();
-      List<double> testMAPE = new List<double>();
-      List<double> trainingR2 = new List<double>();
-      List<double> validationR2 = new List<double>();
-      List<double> testR2 = new List<double>();
-      List<double> size = new List<double>();
-      List<double> height = new List<double>();
-      List<double> targetVariable = new List<double>();
-
-      lock(allVariables) {
-        allVariables.Clear();
-        allVariables[MAPE_TRAINING] = trainingMAPE;
-        allVariables[MAPE_VALIDATION] = validationMAPE;
-        allVariables[MAPE_TEST] = testMAPE;
-        allVariables[R2_TRAINING] = trainingR2;
-        allVariables[R2_VALIDATION] = validationR2;
-        allVariables[R2_TEST] = testR2;
-        allVariables[TREE_SIZE] = size;
-        allVariables[TREE_HEIGHT] = height;
-        allVariables[TARGET_VARIABLE] = targetVariable;
-      }
-
       var results = store.Select(new Statement(anyEntity, new Entity(cedmaNS + "instanceOf"), new Literal("class:GpFunctionTree")))
       .Select(x => store.Select(new SelectFilter(
@@ -108,49 +133,41 @@
           new Resource[] { anyEntity })));
 
-      Random random = new Random(); // for adding random noise to int values
       foreach(Statement[] ss in results) {
-        lock(allVariables) {
-          targetVariable.Add(double.NaN);
-          size.Add(double.NaN);
-          height.Add(double.NaN);
-          trainingMAPE.Add(double.NaN);
-          validationMAPE.Add(double.NaN);
-          testMAPE.Add(double.NaN);
-          trainingR2.Add(double.NaN);
-          validationR2.Add(double.NaN);
-          testR2.Add(double.NaN);
+        if(ss.Length > 0) {
+          Record r = new Record(ss[0].Subject.Uri);
           foreach(Statement s in ss) {
             if(s.Predicate.Equals(targetVariablePredicate)) {
-              ReplaceLastItem(targetVariable, (double)(int)((Literal)s.Property).Value);
+              r.Set(TARGET_VARIABLE, (double)(int)((Literal)s.Property).Value);
             } else if(s.Predicate.Equals(treeSizePredicate)) {
-              ReplaceLastItem(size, (double)(int)((Literal)s.Property).Value);
+              r.Set(TREE_SIZE, (double)(int)((Literal)s.Property).Value);
             } else if(s.Predicate.Equals(treeHeightPredicate)) {
-              ReplaceLastItem(height, (double)(int)((Literal)s.Property).Value);
+              r.Set(TREE_HEIGHT, (double)(int)((Literal)s.Property).Value);
             } else if(s.Predicate.Equals(trainingMAPEPredicate)) {
-              ReplaceLastItem(trainingMAPE, (double)((Literal)s.Property).Value);
+              r.Set(MAPE_TRAINING, (double)((Literal)s.Property).Value);
             } else if(s.Predicate.Equals(validationMAPEPredicate)) {
-              ReplaceLastItem(validationMAPE, (double)((Literal)s.Property).Value);
+              r.Set(MAPE_VALIDATION, (double)((Literal)s.Property).Value);
             } else if(s.Predicate.Equals(testMAPEPredicate)) {
-              ReplaceLastItem(testMAPE, (double)((Literal)s.Property).Value);
+              r.Set(MAPE_TEST, (double)((Literal)s.Property).Value);
             } else if(s.Predicate.Equals(trainingR2Predicate)) {
-              ReplaceLastItem(trainingR2, (double)((Literal)s.Property).Value);
+              r.Set(R2_TRAINING, (double)((Literal)s.Property).Value);
             } else if(s.Predicate.Equals(validationR2Predicate)) {
-              ReplaceLastItem(validationR2, (double)((Literal)s.Property).Value);
+              r.Set(R2_VALIDATION, (double)((Literal)s.Property).Value);
             } else if(s.Predicate.Equals(testR2Predicate)) {
-              ReplaceLastItem(testR2, (double)((Literal)s.Property).Value);
+              r.Set(R2_TEST, (double)((Literal)s.Property).Value);
             }
           }
+          records.Add(r);
+          FireRecordAdded(r);
         }
-        FireChanged();
       }
     }
 
-    private void ReplaceLastItem(List<double> xs, double x) {
-      xs.RemoveAt(xs.Count - 1); xs.Add(x);
+    private void FireRecordAdded(Record r) {
+      if(OnRecordAdded != null) OnRecordAdded(this, new RecordAddedEventArgs(r));
     }
 
     public ResultList()
       : base() {
-      allVariables = new Dictionary<string, List<double>>();
+      records = new List<Record>();
     }
 
@@ -159,18 +176,13 @@
     }
 
-    internal Histogram GetHistogram(string variableName) {
-      Histogram h = new Histogram(50);
-      lock(allVariables) {
-        h.AddValues(allVariables[variableName]);
+    internal void OpenModel(Record r) {
+      IList<Statement> s = store.Select(new Statement(new Entity(r.Uri), rawDataPredicate, anyEntity));
+      if(s.Count == 1) {
+        string rawData = ((SerializedLiteral)s[0].Property).RawData;
+        XmlDocument doc = new XmlDocument();
+        doc.LoadXml(rawData);
+        IItem item = (IItem)PersistenceManager.Restore(doc.ChildNodes[1], new Dictionary<Guid, IStorable>());
+        PluginManager.ControlManager.ShowControl(item.CreateView());
       }
-      return h;
-    }
-
-    internal IList<double> GetValues(string variableName) {
-      List<double> result = new List<double>();
-      lock(allVariables) {
-        result.AddRange(allVariables[variableName]);
-      }
-      return result;
     }
   }
Index: /trunk/sources/HeuristicLab.CEDMA.Charting/ResultListView.cs
===================================================================
--- /trunk/sources/HeuristicLab.CEDMA.Charting/ResultListView.cs	(revision 561)
+++ /trunk/sources/HeuristicLab.CEDMA.Charting/ResultListView.cs	(revision 562)
@@ -41,16 +41,5 @@
 
     private void InitChart() {
-      dataChart.Chart = new BubbleChart(0, 0, 100, 100);
-      foreach(string dim in results.VariableNames) {
-        dataChart.Chart.AddDimension(dim);
-        IList<double> xs = results.GetValues(dim);
-        for(int i = 0; i < xs.Count; i++) {
-          double x = xs[i];
-          if(double.IsInfinity(x) || x == double.MaxValue || x == double.MinValue) x = double.NaN;
-          if(!double.IsNaN(x)) {
-            dataChart.Chart.AddDataPoint(dim, x);
-          }
-        }
-      }
+      dataChart.Chart = new BubbleChart(results, 0, 0, 100, 100);
     }
 
@@ -79,9 +68,9 @@
       // TASK
     }
-    
+
     private void jitterTrackBar_ValueChanged(object sender, EventArgs e) {
       if(dataChart.Chart != null) {
-        double xJitterFactor = xTrackBar.Value / 100.0 ;
-        double yJitterFactor = yTrackBar.Value / 100.0 ;
+        double xJitterFactor = xTrackBar.Value / 100.0;
+        double yJitterFactor = yTrackBar.Value / 100.0;
         dataChart.Chart.SetJitter(xJitterFactor, yJitterFactor);
       }
