Index: trunk/sources/HeuristicLab.CEDMA.Charting/3.3/BubbleChart.cs
===================================================================
--- trunk/sources/HeuristicLab.CEDMA.Charting/3.3/BubbleChart.cs	(revision 2240)
+++ trunk/sources/HeuristicLab.CEDMA.Charting/3.3/BubbleChart.cs	(revision 2289)
@@ -27,13 +27,11 @@
 using HeuristicLab.Charting;
 using System.Windows.Forms;
-using HeuristicLab.CEDMA.Core;
 using HeuristicLab.PluginInfrastructure;
 using HeuristicLab.Core;
 using System.Diagnostics;
+using HeuristicLab.SparseMatrix;
 
 namespace HeuristicLab.CEDMA.Charting {
-  public class BubbleChart : Chart {
-    private const string X_JITTER = "__X_JITTER";
-    private const string Y_JITTER = "__Y_JITTER";
+  public abstract class BubbleChart : Chart {
     private const double maxXJitterPercent = 0.05;
     private const double maxYJitterPercent = 0.05;
@@ -55,32 +53,17 @@
     private double maxX = double.NegativeInfinity;
     private double maxY = double.NegativeInfinity;
-    private List<ResultsEntry> filteredEntries;
-    private Results results;
-    private Dictionary<IPrimitive, ResultsEntry> primitiveToEntryDictionary;
-    private Random random = new Random();
-    private Group points;
-
-    public BubbleChart(Results results, PointD lowerLeft, PointD upperRight)
+
+    protected Group points;
+    protected VisualMatrix matrix;
+    protected Dictionary<IPrimitive, VisualMatrixRow> primitiveToMatrixRowDictionary;
+
+    public BubbleChart(VisualMatrix matrix, PointD lowerLeft, PointD upperRight)
       : base(lowerLeft, upperRight) {
-      primitiveToEntryDictionary = new Dictionary<IPrimitive, ResultsEntry>();
-      this.results = results;
-      filteredEntries = new List<ResultsEntry>();
-
-      foreach (var resultsEntry in results.GetEntries()) {
-        if (resultsEntry.Get(X_JITTER) == null)
-          resultsEntry.Set(X_JITTER, random.NextDouble() * 2.0 - 1.0);
-        if (resultsEntry.Get(Y_JITTER) == null)
-          resultsEntry.Set(Y_JITTER, random.NextDouble() * 2.0 - 1.0);
-      }
-      results.Changed += new EventHandler(results_Changed);
-    }
-
-    void results_Changed(object sender, EventArgs e) {
-      Repaint();
-      EnforceUpdate();
-    }
-
-    public BubbleChart(Results results, double x1, double y1, double x2, double y2)
-      : this(results, new PointD(x1, y1), new PointD(x2, y2)) {
+      primitiveToMatrixRowDictionary = new Dictionary<IPrimitive, VisualMatrixRow>();
+      this.matrix = matrix;
+    }
+
+    public BubbleChart(VisualMatrix matrix, double x1, double y1, double x2, double y2)
+      : this(matrix, new PointD(x1, y1), new PointD(x2, y2)) {
     }
 
@@ -103,5 +86,5 @@
     }
 
-    internal void SetJitter(double xJitterFactor, double yJitterFactor) {
+    public void SetJitter(double xJitterFactor, double yJitterFactor) {
       this.xJitterFactor = xJitterFactor * maxXJitterPercent * Size.Width;
       this.yJitterFactor = yJitterFactor * maxYJitterPercent * Size.Height;
@@ -115,10 +98,10 @@
     }
 
-    private void Repaint() {
+    protected void Repaint() {
       if (xDimension == null || yDimension == null) return;
       double maxSize = 1;
       double minSize = 1;
-      if (sizeDimension != null && results.OrdinalVariables.Contains(sizeDimension)) {
-        var sizes = results.GetEntries()
+      if (sizeDimension != null && matrix.OrdinalVariables.Contains(sizeDimension)) {
+        var sizes = matrix.Rows
           .Select(x => Convert.ToDouble(x.Get(sizeDimension)))
           .Where(size => !double.IsInfinity(size) && size != double.MaxValue && size != double.MinValue)
@@ -132,9 +115,9 @@
       UpdateEnabled = false;
       Group.Clear();
-      primitiveToEntryDictionary.Clear();
+      primitiveToMatrixRowDictionary.Clear();
       points = new Group(this);
       Group.Add(new Axis(this, 0, 0, AxisType.Both));
       UpdateViewSize(0, 0, TransformPixelToWorld(new Size(5, 0)).Width);
-      foreach (ResultsEntry r in results.GetEntries().Where(x => x.Visible)) {
+      foreach (VisualMatrixRow r in matrix.Rows.Where(x => x.Visible)) {
         List<double> xs = new List<double>();
         List<double> ys = new List<double>();
@@ -142,51 +125,51 @@
         List<object> actualYValues = new List<object>();
         int size;
-        if (results.OrdinalVariables.Contains(xDimension) && r.Get(xDimension) != null) {
-          xs.Add(Convert.ToDouble(r.Get(xDimension)) + (double)r.Get(X_JITTER) * xJitterFactor);
+        if (matrix.OrdinalVariables.Contains(xDimension) && r.Get(xDimension) != null) {
+          xs.Add(Convert.ToDouble(r.Get(xDimension)) + r.XJitter * xJitterFactor);
           actualXValues.Add(r.Get(xDimension));
-        } else if (results.CategoricalVariables.Contains(xDimension) && r.Get(xDimension) != null) {
-          xs.Add(results.IndexOfCategoricalValue(xDimension, r.Get(xDimension)) + (double)r.Get(X_JITTER) * xJitterFactor);
+        } else if (matrix.CategoricalVariables.Contains(xDimension) && r.Get(xDimension) != null) {
+          xs.Add(matrix.IndexOfCategoricalValue(xDimension, r.Get(xDimension)) + r.XJitter * xJitterFactor);
           actualXValues.Add(r.Get(xDimension));
-        } else if (results.MultiDimensionalCategoricalVariables.Contains(xDimension)) {
+        } else if (matrix.MultiDimensionalCategoricalVariables.Contains(xDimension)) {
           var path = xDimension.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim());
-          IEnumerable<ResultsEntry> subEntries = (IEnumerable<ResultsEntry>)r.Get(path.ElementAt(0));
-          foreach (ResultsEntry subEntry in subEntries) {
-            if (subEntry.Get(path.ElementAt(1)) != null) {
-              xs.Add(results.IndexOfCategoricalValue(xDimension, subEntry.Get(path.ElementAt(1))) + (double)r.Get(X_JITTER) * xJitterFactor);
-              actualXValues.Add(subEntry.Get(path.ElementAt(1)));
-            }
-          }
-        } else if (results.MultiDimensionalOrdinalVariables.Contains(xDimension)) {
+          IEnumerable<VisualMatrixRow> subRows = (IEnumerable<VisualMatrixRow>)r.Get(path.ElementAt(0));
+          foreach (VisualMatrixRow subRow in subRows) {
+            if (subRow.Get(path.ElementAt(1)) != null) {
+              xs.Add(matrix.IndexOfCategoricalValue(xDimension, subRow.Get(path.ElementAt(1))) + r.YJitter * xJitterFactor);
+              actualXValues.Add(subRow.Get(path.ElementAt(1)));
+            }
+          }
+        } else if (matrix.MultiDimensionalOrdinalVariables.Contains(xDimension)) {
           var path = xDimension.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim());
-          IEnumerable<ResultsEntry> subEntries = (IEnumerable<ResultsEntry>)r.Get(path.ElementAt(0));
-          foreach (ResultsEntry subEntry in subEntries) {
-            if (subEntry.Get(path.ElementAt(1)) != null) {
-              xs.Add(Convert.ToDouble(subEntry.Get(path.ElementAt(1))) + (double)r.Get(X_JITTER) * xJitterFactor);
-              actualXValues.Add(subEntry.Get(path.ElementAt(1)));
-            }
-          }
-        }
-        if (results.OrdinalVariables.Contains(yDimension) && r.Get(yDimension) != null) {
-          ys.Add(Convert.ToDouble(r.Get(yDimension)) + (double)r.Get(Y_JITTER) * yJitterFactor);
+          IEnumerable<VisualMatrixRow> subRows = (IEnumerable<VisualMatrixRow>)r.Get(path.ElementAt(0));
+          foreach (VisualMatrixRow subRow in subRows) {
+            if (subRow.Get(path.ElementAt(1)) != null) {
+              xs.Add(Convert.ToDouble(subRow.Get(path.ElementAt(1))) + r.XJitter * xJitterFactor);
+              actualXValues.Add(subRow.Get(path.ElementAt(1)));
+            }
+          }
+        }
+        if (matrix.OrdinalVariables.Contains(yDimension) && r.Get(yDimension) != null) {
+          ys.Add(Convert.ToDouble(r.Get(yDimension)) + r.YJitter * yJitterFactor);
           actualYValues.Add(r.Get(yDimension));
-        } else if (results.CategoricalVariables.Contains(yDimension) && r.Get(yDimension) != null) {
-          ys.Add(results.IndexOfCategoricalValue(yDimension, r.Get(yDimension)) + (double)r.Get(Y_JITTER) * yJitterFactor);
+        } else if (matrix.CategoricalVariables.Contains(yDimension) && r.Get(yDimension) != null) {
+          ys.Add(matrix.IndexOfCategoricalValue(yDimension, r.Get(yDimension)) + r.YJitter * yJitterFactor);
           actualYValues.Add(r.Get(yDimension));
-        } else if (results.MultiDimensionalCategoricalVariables.Contains(yDimension)) {
+        } else if (matrix.MultiDimensionalCategoricalVariables.Contains(yDimension)) {
           var path = yDimension.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim());
-          IEnumerable<ResultsEntry> subEntries = (IEnumerable<ResultsEntry>)r.Get(path.ElementAt(0));
-          foreach (ResultsEntry subEntry in subEntries) {
-            if (subEntry.Get(path.ElementAt(1)) != null) {
-              ys.Add(results.IndexOfCategoricalValue(yDimension, subEntry.Get(path.ElementAt(1))) + (double)r.Get(Y_JITTER) * yJitterFactor);
-              actualYValues.Add(subEntry.Get(path.ElementAt(1)));
-            }
-          }
-        } else if (results.MultiDimensionalOrdinalVariables.Contains(yDimension)) {
+          IEnumerable<VisualMatrixRow> subRows = (IEnumerable<VisualMatrixRow>)r.Get(path.ElementAt(0));
+          foreach (VisualMatrixRow subRow in subRows) {
+            if (subRow.Get(path.ElementAt(1)) != null) {
+              ys.Add(matrix.IndexOfCategoricalValue(yDimension, subRow.Get(path.ElementAt(1))) + r.YJitter * yJitterFactor);
+              actualYValues.Add(subRow.Get(path.ElementAt(1)));
+            }
+          }
+        } else if (matrix.MultiDimensionalOrdinalVariables.Contains(yDimension)) {
           var path = yDimension.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim());
-          IEnumerable<ResultsEntry> subEntries = (IEnumerable<ResultsEntry>)r.Get(path.ElementAt(0));
-          foreach (ResultsEntry subEntry in subEntries) {
-            if (subEntry.Get(path.ElementAt(1)) != null) {
-              ys.Add(Convert.ToDouble(subEntry.Get(path.ElementAt(1))) + (double)r.Get(Y_JITTER) * yJitterFactor);
-              actualYValues.Add(subEntry.Get(path.ElementAt(1)));
+          IEnumerable<VisualMatrixRow> subRows = (IEnumerable<VisualMatrixRow>)r.Get(path.ElementAt(0));
+          foreach (VisualMatrixRow subRow in subRows) {
+            if (subRow.Get(path.ElementAt(1)) != null) {
+              ys.Add(Convert.ToDouble(subRow.Get(path.ElementAt(1))) + r.YJitter * yJitterFactor);
+              actualYValues.Add(subRow.Get(path.ElementAt(1)));
             }
           }
@@ -208,5 +191,5 @@
           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) && IsReasonablePoint(new PointD(x,y))) {
+          if (!double.IsNaN(x) && !double.IsNaN(y) && IsReasonablePoint(new PointD(x, y))) {
             string actualXValue = actualXValues[Math.Min(i, actualXValues.Count() - 1)].ToString();
             string actualYValue = actualYValues[Math.Min(i, actualYValues.Count() - 1)].ToString();
@@ -221,5 +204,5 @@
             points.Add(c);
             if (!r.Selected) c.IntoBackground();
-            primitiveToEntryDictionary[c] = r;
+            primitiveToMatrixRowDictionary[c] = r;
           }
         }
@@ -230,5 +213,5 @@
 
     private bool IsReasonablePoint(PointD pointD) {
-      return pointD.X > LowerLeft.X && pointD.X < UpperRight.X && pointD.Y > LowerLeft.Y && pointD.Y < UpperRight.Y; 
+      return pointD.X > LowerLeft.X && pointD.X < UpperRight.X && pointD.Y > LowerLeft.Y && pointD.Y < UpperRight.Y;
     }
 
@@ -274,94 +257,42 @@
     }
 
-    internal ResultsEntry GetResultsEntry(Point point) {
-      ResultsEntry r = null;
+    protected VisualMatrixRow GetMatrixRow(Point point) {
+      VisualMatrixRow r = null;
       IPrimitive p = points.GetPrimitive(TransformPixelToWorld(point));
       if (p != null) {
-        primitiveToEntryDictionary.TryGetValue(p, out r);
+        primitiveToMatrixRowDictionary.TryGetValue(p, out r);
       }
       return r;
     }
 
-    public override void MouseDrag(Point start, Point end, MouseButtons button) {
-      if (button == MouseButtons.Left && Mode == ChartMode.Select) {
-        PointD a = TransformPixelToWorld(start);
-        PointD b = TransformPixelToWorld(end);
-        double minX = Math.Min(a.X, b.X);
-        double minY = Math.Min(a.Y, b.Y);
-        double maxX = Math.Max(a.X, b.X);
-        double maxY = Math.Max(a.Y, b.Y);
-        HeuristicLab.Charting.Rectangle rect = new HeuristicLab.Charting.Rectangle(this, minX, minY, maxX, maxY);
-
-        List<IPrimitive> primitives = new List<IPrimitive>();
-        primitives.AddRange(points.Primitives);
-
-        foreach (FixedSizeCircle p in primitives) {
-          if (rect.ContainsPoint(p.Point)) {
-            ResultsEntry r;
-            primitiveToEntryDictionary.TryGetValue(p, out r);
-            if (r != null) r.ToggleSelected();
-          }
-        }
-        if (primitives.Count() > 0) results.FireChanged();
-      } else {
-        base.MouseDrag(start, end, button);
-      }
-    }
-
-    public override void MouseClick(Point point, MouseButtons button) {
-      if (button == MouseButtons.Left) {
-        ResultsEntry r = GetResultsEntry(point);
-        if (r != null) {
-          r.ToggleSelected();
-          results.FireChanged();
-        }
-      } else {
-        base.MouseClick(point, button);
-      }
-    }
-
-    public override void MouseDoubleClick(Point point, MouseButtons button) {
-      if (button == MouseButtons.Left) {
-        ResultsEntry entry = GetResultsEntry(point);
-        if (entry != null) {
-          var model = (IItem)PersistenceManager.RestoreFromGZip((byte[])entry.Get("PersistedData"));
-          PluginManager.ControlManager.ShowControl(model.CreateView());
-        }
-      } else {
-        base.MouseDoubleClick(point, button);
-      }
-    }
-
-    internal void ToggleSelected() {
-      foreach (ResultsEntry entry in results.GetEntries()) {
+    public virtual void ToggleSelected() {
+      foreach (VisualMatrixRow row in matrix.Rows) {
+        row.ToggleSelected();
+      }
+      matrix.FireChanged();
+    }
+
+    public virtual void ClearSelection() {
+      foreach (VisualMatrixRow entry in matrix.Rows.Where(x => x.Selected)) {
         entry.ToggleSelected();
       }
-      results.FireChanged();
-    }
-
-    internal void ClearSelection() {
-      foreach (ResultsEntry entry in results.GetEntries().Where(x=>x.Selected)) {
-        entry.ToggleSelected();
-      }
-      results.FireChanged();
-    }
-
-    internal void ApplyFilter(Func<ResultsEntry, bool> filterPred) {
-      foreach (ResultsEntry r in results.GetEntries()) {
+      matrix.FireChanged();
+    }
+
+    public virtual void ApplyFilter(Func<VisualMatrixRow, bool> filterPred) {
+      foreach (VisualMatrixRow r in matrix.Rows) {
         if (filterPred(r)) {
           r.Visible = false;
           r.Selected = false;
-          filteredEntries.Add(r);
-        } 
-      }
-      results.FireChanged();
-    }
-
-    internal void ClearFilter() {
-      foreach (ResultsEntry r in filteredEntries) {
+        }
+      }
+      matrix.FireChanged();
+    }
+
+    public virtual void ClearFilter() {
+      foreach (VisualMatrixRow r in matrix.Rows.Where(x => !x.Visible)) {
         r.Visible = true;
       }
-      filteredEntries.Clear();
-      results.FireChanged();
+      matrix.FireChanged();
     }
   }
Index: trunk/sources/HeuristicLab.CEDMA.Charting/3.3/BubbleChartControl.Designer.cs
===================================================================
--- trunk/sources/HeuristicLab.CEDMA.Charting/3.3/BubbleChartControl.Designer.cs	(revision 2240)
+++ trunk/sources/HeuristicLab.CEDMA.Charting/3.3/BubbleChartControl.Designer.cs	(revision 2289)
@@ -51,10 +51,10 @@
       this.zoomToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
       this.selectToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+      this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
+      this.clearSelectionMenuItem = new System.Windows.Forms.ToolStripMenuItem();
       this.invertSelectionToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
       this.filterToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+      this.showHiddenToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
       this.toolTip = new System.Windows.Forms.ToolTip(this.components);
-      this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
-      this.clearSelectionMenuItem = new System.Windows.Forms.ToolStripMenuItem();
-      this.showHiddenToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
       ((System.ComponentModel.ISupportInitialize)(this.pictureBox)).BeginInit();
       this.pictureBoxContextMenuStrip.SuspendLayout();
@@ -95,4 +95,5 @@
       this.pictureBoxContextMenuStrip.Name = "pictureBoxContextMenuStrip";
       this.pictureBoxContextMenuStrip.Size = new System.Drawing.Size(155, 186);
+      this.pictureBoxContextMenuStrip.Opening += new System.ComponentModel.CancelEventHandler(this.pictureBoxContextMenuStrip_Opening);
       // 
       // moveToolStripMenuItem
@@ -117,4 +118,16 @@
       this.selectToolStripMenuItem.Click += new System.EventHandler(this.selectToolStripMenuItem_Click);
       // 
+      // toolStripSeparator1
+      // 
+      this.toolStripSeparator1.Name = "toolStripSeparator1";
+      this.toolStripSeparator1.Size = new System.Drawing.Size(151, 6);
+      // 
+      // clearSelectionMenuItem
+      // 
+      this.clearSelectionMenuItem.Name = "clearSelectionMenuItem";
+      this.clearSelectionMenuItem.Size = new System.Drawing.Size(154, 22);
+      this.clearSelectionMenuItem.Text = "Clear selection";
+      this.clearSelectionMenuItem.Click += new System.EventHandler(this.clearSelectionMenuItem_Click);
+      // 
       // invertSelectionToolStripMenuItem
       // 
@@ -131,16 +144,4 @@
       this.filterToolStripMenuItem.Click += new System.EventHandler(this.hideSelectedToolStripMenuItem_Click);
       // 
-      // toolStripSeparator1
-      // 
-      this.toolStripSeparator1.Name = "toolStripSeparator1";
-      this.toolStripSeparator1.Size = new System.Drawing.Size(151, 6);
-      // 
-      // clearSelectionMenuItem
-      // 
-      this.clearSelectionMenuItem.Name = "clearSelectionMenuItem";
-      this.clearSelectionMenuItem.Size = new System.Drawing.Size(154, 22);
-      this.clearSelectionMenuItem.Text = "Clear selection";
-      this.clearSelectionMenuItem.Click += new System.EventHandler(this.clearSelectionMenuItem_Click);
-      // 
       // showHiddenToolStripMenuItem
       // 
@@ -150,4 +151,8 @@
       this.showHiddenToolStripMenuItem.Text = "Show hidden";
       this.showHiddenToolStripMenuItem.Click += new System.EventHandler(this.showHiddenToolStripMenuItem_Click);
+      // 
+      // toolTip
+      // 
+      this.toolTip.Popup += new System.Windows.Forms.PopupEventHandler(this.toolTip_Popup);
       // 
       // BubbleChartControl
Index: trunk/sources/HeuristicLab.CEDMA.Charting/3.3/BubbleChartControl.cs
===================================================================
--- trunk/sources/HeuristicLab.CEDMA.Charting/3.3/BubbleChartControl.cs	(revision 2240)
+++ trunk/sources/HeuristicLab.CEDMA.Charting/3.3/BubbleChartControl.cs	(revision 2289)
@@ -195,4 +195,12 @@
       showHiddenToolStripMenuItem.Enabled = false;
     }
+
+    private void pictureBoxContextMenuStrip_Opening(object sender, CancelEventArgs e) {
+
+    }
+
+    private void toolTip_Popup(object sender, PopupEventArgs e) {
+
+    }
   }
 }
Index: trunk/sources/HeuristicLab.CEDMA.Charting/3.3/BubbleChartView.cs
===================================================================
--- trunk/sources/HeuristicLab.CEDMA.Charting/3.3/BubbleChartView.cs	(revision 2240)
+++ trunk/sources/HeuristicLab.CEDMA.Charting/3.3/BubbleChartView.cs	(revision 2289)
@@ -9,29 +9,24 @@
 using HeuristicLab.Core;
 using HeuristicLab.CEDMA.Charting;
-using HeuristicLab.CEDMA.Core;
 using HeuristicLab.PluginInfrastructure;
+using HeuristicLab.SparseMatrix;
 
 namespace HeuristicLab.CEDMA.Charting {
   public partial class BubbleChartView : ViewBase {
-    private Results Results {
-      get { return (Results)Item; }
-      set { Item = value; }
-    }
     private const string CONSTANT_SIZE = "<constant>";
     private Label pleaseSelectAxisLabel = new Label();
-    public BubbleChartView(Results results) {
+    public BubbleChartView(VisualMatrix results) {
       InitializeComponent();
-      Results = results;
-      bubbleChartControl.Chart = new BubbleChart(Results, 0, 0, 100, 100);
-      xAxisComboBox.Items.AddRange(Results.OrdinalVariables);
-      xAxisComboBox.Items.AddRange(Results.CategoricalVariables);
-      xAxisComboBox.Items.AddRange(Results.MultiDimensionalCategoricalVariables);
-      xAxisComboBox.Items.AddRange(Results.MultiDimensionalOrdinalVariables);
-      yAxisComboBox.Items.AddRange(Results.OrdinalVariables);
-      yAxisComboBox.Items.AddRange(Results.CategoricalVariables);
-      yAxisComboBox.Items.AddRange(Results.MultiDimensionalCategoricalVariables);
-      yAxisComboBox.Items.AddRange(Results.MultiDimensionalOrdinalVariables);
+      bubbleChartControl.Chart = new ModelingBubbleChart(results, 0, 0, 100, 100);
+      xAxisComboBox.Items.AddRange(results.OrdinalVariables);
+      xAxisComboBox.Items.AddRange(results.CategoricalVariables);
+      xAxisComboBox.Items.AddRange(results.MultiDimensionalCategoricalVariables);
+      xAxisComboBox.Items.AddRange(results.MultiDimensionalOrdinalVariables);
+      yAxisComboBox.Items.AddRange(results.OrdinalVariables);
+      yAxisComboBox.Items.AddRange(results.CategoricalVariables);
+      yAxisComboBox.Items.AddRange(results.MultiDimensionalCategoricalVariables);
+      yAxisComboBox.Items.AddRange(results.MultiDimensionalOrdinalVariables);
       sizeComboBox.Items.Add(CONSTANT_SIZE);
-      sizeComboBox.Items.AddRange(Results.OrdinalVariables);
+      sizeComboBox.Items.AddRange(results.OrdinalVariables);
       sizeComboBox.SelectedItem = sizeComboBox.Items[0];
       yAxisComboBox.SelectedItem = yAxisComboBox.Items[0];
@@ -68,5 +63,5 @@
     }
 
-    public IControl CreateView(Results results) {
+    public IControl CreateView(VisualMatrix results) {
       return new BubbleChartView(results);
     }
Index: trunk/sources/HeuristicLab.CEDMA.Charting/3.3/HeuristicLab.CEDMA.Charting-3.3.csproj
===================================================================
--- trunk/sources/HeuristicLab.CEDMA.Charting/3.3/HeuristicLab.CEDMA.Charting-3.3.csproj	(revision 2240)
+++ trunk/sources/HeuristicLab.CEDMA.Charting/3.3/HeuristicLab.CEDMA.Charting-3.3.csproj	(revision 2289)
@@ -96,11 +96,17 @@
     </Compile>
     <Compile Include="HeuristicLabCedmaChartingPlugin.cs" />
+    <Compile Include="IResultsViewFactory.cs" />
+    <Compile Include="ModelingBubbleChart.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="TableResultsView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="TableResultsView.Designer.cs">
+      <DependentUpon>TableResultsView.cs</DependentUpon>
+    </Compile>
+    <Compile Include="VisualMatrix.cs" />
+    <Compile Include="VisualMatrixRow.cs" />
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="..\..\HeuristicLab.CEDMA.Core\3.3\HeuristicLab.CEDMA.Core-3.3.csproj">
-      <Project>{C27DDF6C-84DF-45EF-B82F-57A28DD51166}</Project>
-      <Name>HeuristicLab.CEDMA.Core-3.3</Name>
-    </ProjectReference>
     <ProjectReference Include="..\..\HeuristicLab.Charting.Data\3.2\HeuristicLab.Charting.Data-3.2.csproj">
       <Project>{E0740131-AA3E-4A3F-BA03-C9FF8327F4EE}</Project>
@@ -119,4 +125,8 @@
       <Name>HeuristicLab.PluginInfrastructure</Name>
     </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.SparseMatrix\3.2\HeuristicLab.SparseMatrix-3.2.csproj">
+      <Project>{1263BB36-1F20-4960-A5CB-530746DBAD77}</Project>
+      <Name>HeuristicLab.SparseMatrix-3.2</Name>
+    </ProjectReference>
   </ItemGroup>
   <ItemGroup>
@@ -130,4 +140,7 @@
     <EmbeddedResource Include="BubbleChartView.resx">
       <DependentUpon>BubbleChartView.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="TableResultsView.resx">
+      <DependentUpon>TableResultsView.cs</DependentUpon>
     </EmbeddedResource>
   </ItemGroup>
Index: trunk/sources/HeuristicLab.CEDMA.Charting/3.3/HeuristicLabCedmaChartingPlugin.cs
===================================================================
--- trunk/sources/HeuristicLab.CEDMA.Charting/3.3/HeuristicLabCedmaChartingPlugin.cs	(revision 2240)
+++ trunk/sources/HeuristicLab.CEDMA.Charting/3.3/HeuristicLabCedmaChartingPlugin.cs	(revision 2289)
@@ -28,9 +28,9 @@
   [ClassInfo(Name = "HeuristicLab.CEDMA.Charting-3.3")]
   [PluginFile(Filename = "HeuristicLab.CEDMA.Charting-3.3.dll", Filetype = PluginFileType.Assembly)]
-  [Dependency(Dependency = "HeuristicLab.CEDMA.Core-3.3")]
   [Dependency(Dependency = "HeuristicLab.Charting-3.2")]
   [Dependency(Dependency = "HeuristicLab.Charting.Data-3.2")]
   [Dependency(Dependency = "HeuristicLab.Core-3.2")]
   [Dependency(Dependency = "HeuristicLab.Data-3.2")]
+  [Dependency(Dependency = "HeuristicLab.SparseMatrix-3.2")]
   public class HeuristicLabCedmaCorePlugin : PluginBase {
   }
Index: trunk/sources/HeuristicLab.CEDMA.Charting/3.3/IResultsViewFactory.cs
===================================================================
--- trunk/sources/HeuristicLab.CEDMA.Charting/3.3/IResultsViewFactory.cs	(revision 2289)
+++ trunk/sources/HeuristicLab.CEDMA.Charting/3.3/IResultsViewFactory.cs	(revision 2289)
@@ -0,0 +1,36 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 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.Text;
+using HeuristicLab.Core;
+using System.Xml;
+using System.Windows.Forms;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.CEDMA.Charting {
+  public interface IResultsViewFactory {
+    string Name { get; }
+    IControl CreateView(VisualMatrix results);
+  }
+}
Index: trunk/sources/HeuristicLab.CEDMA.Charting/3.3/ModelingBubbleChart.cs
===================================================================
--- trunk/sources/HeuristicLab.CEDMA.Charting/3.3/ModelingBubbleChart.cs	(revision 2289)
+++ trunk/sources/HeuristicLab.CEDMA.Charting/3.3/ModelingBubbleChart.cs	(revision 2289)
@@ -0,0 +1,103 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 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.Text;
+using System.Drawing;
+using System.Linq;
+using HeuristicLab.Charting;
+using System.Windows.Forms;
+using HeuristicLab.PluginInfrastructure;
+using HeuristicLab.Core;
+using System.Diagnostics;
+using HeuristicLab.SparseMatrix;
+
+
+namespace HeuristicLab.CEDMA.Charting {
+  public class ModelingBubbleChart :BubbleChart {
+    public ModelingBubbleChart(VisualMatrix matrix, PointD lowerLeft, PointD upperRight)
+      : base(matrix,lowerLeft, upperRight) {
+
+      matrix.Changed += new EventHandler(matrix_Changed);
+    }
+
+    public ModelingBubbleChart(VisualMatrix matrix, double x1, double y1, double x2, double y2)
+      : this(matrix, new PointD(x1, y1), new PointD(x2, y2)) {
+    }
+
+    public void matrix_Changed(object sender, EventArgs e) {
+      Repaint();
+      EnforceUpdate();
+    }
+
+    public override void MouseDoubleClick(Point point, MouseButtons button) {
+      if (button == MouseButtons.Left) {
+        VisualMatrixRow row = GetMatrixRow(point);
+        if (row != null) {
+          var model = (IItem)PersistenceManager.RestoreFromGZip((byte[])row.Get("PersistedData"));
+          if (model != null)
+            PluginManager.ControlManager.ShowControl(model.CreateView());
+        }
+      } else {
+        base.MouseDoubleClick(point, button);
+      }
+    }
+
+    public override void MouseDrag(Point start, Point end, MouseButtons button) {
+      if (button == MouseButtons.Left && Mode == ChartMode.Select) {
+        PointD a = TransformPixelToWorld(start);
+        PointD b = TransformPixelToWorld(end);
+        double minX = Math.Min(a.X, b.X);
+        double minY = Math.Min(a.Y, b.Y);
+        double maxX = Math.Max(a.X, b.X);
+        double maxY = Math.Max(a.Y, b.Y);
+        HeuristicLab.Charting.Rectangle rect = new HeuristicLab.Charting.Rectangle(this, minX, minY, maxX, maxY);
+
+        List<IPrimitive> primitives = new List<IPrimitive>();
+        primitives.AddRange(points.Primitives);
+
+        foreach (FixedSizeCircle p in primitives) {
+          if (rect.ContainsPoint(p.Point)) {
+            VisualMatrixRow r;
+            primitiveToMatrixRowDictionary.TryGetValue(p, out r);
+            if (r != null) r.ToggleSelected();
+          }
+        }
+        if (primitives.Count() > 0) matrix.FireChanged();
+      } else {
+        base.MouseDrag(start, end, button);
+      }
+    }
+
+    public override void MouseClick(Point point, MouseButtons button) {
+      if (button == MouseButtons.Left) {
+        VisualMatrixRow r = GetMatrixRow(point);
+        if (r != null) {
+          r.ToggleSelected();
+          matrix.FireChanged();
+        }
+      } else {
+        base.MouseClick(point, button);
+      }
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.CEDMA.Charting/3.3/TableResultsView.Designer.cs
===================================================================
--- trunk/sources/HeuristicLab.CEDMA.Charting/3.3/TableResultsView.Designer.cs	(revision 2289)
+++ trunk/sources/HeuristicLab.CEDMA.Charting/3.3/TableResultsView.Designer.cs	(revision 2289)
@@ -0,0 +1,61 @@
+﻿namespace HeuristicLab.CEDMA.Core {
+  partial class TableResultsView {
+    /// <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.dataGridView = new System.Windows.Forms.DataGridView();
+      ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // dataGridView
+      // 
+      this.dataGridView.AllowUserToAddRows = false;
+      this.dataGridView.AllowUserToDeleteRows = false;
+      this.dataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
+      this.dataGridView.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.dataGridView.Location = new System.Drawing.Point(0, 0);
+      this.dataGridView.Name = "dataGridView";
+      this.dataGridView.ReadOnly = true;
+      this.dataGridView.Size = new System.Drawing.Size(450, 459);
+      this.dataGridView.TabIndex = 0;
+      this.dataGridView.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.dataGridView_MouseDoubleClick);
+      this.dataGridView.SelectionChanged += new System.EventHandler(this.dataGridView_SelectionChanged);
+      // 
+      // TableResultsView
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Controls.Add(this.dataGridView);
+      this.Name = "TableResultsView";
+      this.Size = new System.Drawing.Size(450, 459);
+      ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).EndInit();
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.DataGridView dataGridView;
+
+  }
+}
Index: trunk/sources/HeuristicLab.CEDMA.Charting/3.3/TableResultsView.cs
===================================================================
--- trunk/sources/HeuristicLab.CEDMA.Charting/3.3/TableResultsView.cs	(revision 2289)
+++ trunk/sources/HeuristicLab.CEDMA.Charting/3.3/TableResultsView.cs	(revision 2289)
@@ -0,0 +1,89 @@
+﻿using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Data;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using HeuristicLab.Core;
+using HeuristicLab.CEDMA.Core;
+using HeuristicLab.PluginInfrastructure;
+using HeuristicLab.CEDMA.Charting;
+
+namespace HeuristicLab.CEDMA.Core {
+
+  public partial class TableResultsView : ViewBase {
+    private VisualMatrix VisualMatrix {
+      get { return (VisualMatrix)Item; }
+      set { Item = value; }
+    }
+    private bool suppressEvents;
+    public TableResultsView(VisualMatrix visualMatrix) {
+      suppressEvents = false;
+      InitializeComponent();
+      VisualMatrix = visualMatrix;
+      VisualMatrix.Changed += new EventHandler(VisualMatrixChanged);
+    }
+
+    private void VisualMatrixChanged(object sender, EventArgs e) {
+      if (suppressEvents) return;
+      UpdateControls();
+    }
+
+    protected override void UpdateControls() {
+      suppressEvents = true;
+      dataGridView.Rows.Clear();
+      dataGridView.Columns.Clear();
+      foreach (var attribute in VisualMatrix.Attributes) {
+        dataGridView.Columns.Add(attribute, attribute);
+      }
+
+      foreach (var row in VisualMatrix.Rows) {
+        if (row.Visible) {
+          int rowIndex = dataGridView.Rows.Add();
+          dataGridView.Rows[rowIndex].Tag = row;
+          foreach (string attrName in VisualMatrix.Attributes) {
+            dataGridView.Rows[rowIndex].Cells[attrName].Value = row.Get(attrName);
+          }
+          if (row.Selected) dataGridView.Rows[rowIndex].Selected = true;
+        }
+      }
+      dataGridView.Update();
+      suppressEvents = false;
+    }
+
+    private void dataGridView_SelectionChanged(object sender, EventArgs e) {
+      if (suppressEvents) return;
+      foreach (DataGridViewRow row in dataGridView.Rows) {
+        ((VisualMatrixRow)row.Tag).Selected = row.Selected;
+      }
+      suppressEvents = true;
+      VisualMatrix.FireChanged();
+      suppressEvents = false;
+    }
+
+    private void dataGridView_MouseDoubleClick(object sender, MouseEventArgs e) {
+      if (e.Button == MouseButtons.Left && e.Clicks == 2) {
+        DataGridView.HitTestInfo hitInfo = dataGridView.HitTest(e.X, e.Y);
+        VisualMatrixRow entry = (VisualMatrixRow)dataGridView.Rows[hitInfo.RowIndex].Tag;        
+        var model = (IItem)PersistenceManager.RestoreFromGZip((byte[])entry.Get("PersistedData"));
+        PluginManager.ControlManager.ShowControl(model.CreateView());
+      }
+    }
+  }
+
+  public class TablesResultsViewFactory : IResultsViewFactory {
+    #region IResultsViewFactory Members
+
+    public string Name {
+      get { return "Table"; }
+    }
+
+    public IControl CreateView(VisualMatrix matrix) {
+      return new TableResultsView(matrix);
+    }
+
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.CEDMA.Charting/3.3/TableResultsView.resx
===================================================================
--- trunk/sources/HeuristicLab.CEDMA.Charting/3.3/TableResultsView.resx	(revision 2289)
+++ trunk/sources/HeuristicLab.CEDMA.Charting/3.3/TableResultsView.resx	(revision 2289)
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
Index: trunk/sources/HeuristicLab.CEDMA.Charting/3.3/VisualMatrix.cs
===================================================================
--- trunk/sources/HeuristicLab.CEDMA.Charting/3.3/VisualMatrix.cs	(revision 2289)
+++ trunk/sources/HeuristicLab.CEDMA.Charting/3.3/VisualMatrix.cs	(revision 2289)
@@ -0,0 +1,80 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using HeuristicLab.Core;
+using HeuristicLab.SparseMatrix;
+
+namespace HeuristicLab.CEDMA.Charting {
+  public class VisualMatrix : ItemBase {
+    private Dictionary<string, Dictionary<object, double>> categoricalValueIndices;
+    private Matrix matrix;
+
+    public VisualMatrix(Matrix matrix, string[] categoricalVariables, string[] ordinalVariables,
+      string[] multiDimensionalCategoricalVariables,string[] multiDimensionalOrdinalVariables) {
+      this.matrix = matrix;
+      this.rows = new List<VisualMatrixRow>();
+      foreach(MatrixRow row in matrix.GetRows())
+        rows.Add(new VisualMatrixRow(row));
+
+      this.categoricalVariables = categoricalVariables;
+      this.ordinalVariables = ordinalVariables;
+      this.multiDimensionalOrdinalVariables = multiDimensionalOrdinalVariables;
+      this.multiDimensionalCategoricalVariables = multiDimensionalCategoricalVariables;
+      this.categoricalValueIndices = new Dictionary<string, Dictionary<object, double>>();
+
+      matrix.Changed += new EventHandler(MatrixChanged);
+    }
+
+    private List<VisualMatrixRow> rows;
+    public IEnumerable<VisualMatrixRow> Rows {
+      get {
+        return rows;
+      }
+    }
+
+    private string[] categoricalVariables;
+    public string[] CategoricalVariables {
+      get { return categoricalVariables; }
+    }
+
+    private string[] ordinalVariables;
+    public string[] OrdinalVariables {
+      get { return ordinalVariables; }
+    }
+
+    private string[] multiDimensionalOrdinalVariables;
+    public string[] MultiDimensionalOrdinalVariables {
+      get { return multiDimensionalOrdinalVariables; }
+    }
+
+    private string[] multiDimensionalCategoricalVariables;
+    public string[] MultiDimensionalCategoricalVariables {
+      get { return multiDimensionalCategoricalVariables; }
+    }
+    
+    public double IndexOfCategoricalValue(string variable, object value) {
+      if (value == null) return double.NaN;
+      Dictionary<object, double> valueToIndexMap;
+      if (categoricalValueIndices.ContainsKey(variable)) {
+        valueToIndexMap = categoricalValueIndices[variable];
+      } else {
+        valueToIndexMap = new Dictionary<object, double>();
+        categoricalValueIndices[variable] = valueToIndexMap;
+      }
+      if (!valueToIndexMap.ContainsKey(value)) {
+        if (valueToIndexMap.Values.Count == 0) valueToIndexMap[value] = 1.0;
+        else valueToIndexMap[value] = 1.0 + valueToIndexMap.Values.Max();
+      }
+      return valueToIndexMap[value];
+    }
+
+    private void MatrixChanged(object sender, EventArgs e) {
+      this.FireChanged();
+    }
+
+     public IEnumerable<string> Attributes {
+      get {return CategoricalVariables.Concat(OrdinalVariables);}
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.CEDMA.Charting/3.3/VisualMatrixRow.cs
===================================================================
--- trunk/sources/HeuristicLab.CEDMA.Charting/3.3/VisualMatrixRow.cs	(revision 2289)
+++ trunk/sources/HeuristicLab.CEDMA.Charting/3.3/VisualMatrixRow.cs	(revision 2289)
@@ -0,0 +1,63 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using HeuristicLab.Core;
+using HeuristicLab.SparseMatrix;
+
+namespace HeuristicLab.CEDMA.Charting {
+  public class VisualMatrixRow {
+    private MatrixRow row;
+    private static Random random = new Random();
+
+    public VisualMatrixRow(MatrixRow row) {
+      this.row = row;
+      this.visible = true;
+      this.selected = false;
+      this.xJitter = random.NextDouble() * 2.0 - 1.0;
+      this.yJitter = random.NextDouble() * 2.0 - 1.0;
+    }
+
+    private bool visible;
+    public bool Visible {
+      get { return this.visible; }
+      set { this.visible = value; }
+    }
+
+    private bool selected;
+    public bool Selected {
+      get { return this.selected; }
+      set { this.selected = value; }
+    }
+
+    private double xJitter;
+    public double XJitter {
+      get { return xJitter; }
+    }
+
+    private double yJitter;
+    public double YJitter {
+      get { return yJitter; }
+    }
+
+    public object Get(string name) {
+      return row.Get(name);
+    }
+
+    public void ToggleSelected() {
+      selected = !selected;
+    }
+
+    public string GetToolTipText() {
+      StringBuilder b = new StringBuilder();
+      foreach (KeyValuePair<string, object> v in row.Values) {
+        if (v.Value is string || v.Value is double || v.Value is int) {
+          string val = v.Value.ToString();
+          if (val.Length > 40) val = val.Substring(0, 38) + "...";
+          b.Append(v.Key).Append(" = ").Append(val).AppendLine();
+        }
+      }
+      return b.ToString();
+    }
+  }
+}
