Index: /trunk/sources/HeuristicLab.Analysis.Views/3.3/HeatMapView.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Analysis.Views/3.3/HeatMapView.Designer.cs	(revision 4738)
+++ /trunk/sources/HeuristicLab.Analysis.Views/3.3/HeatMapView.Designer.cs	(revision 4739)
@@ -46,16 +46,15 @@
     private void InitializeComponent() {
       System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
-      System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
-      System.Windows.Forms.DataVisualization.Charting.Title title1= new System.Windows.Forms.DataVisualization.Charting.Title();
+      System.Windows.Forms.DataVisualization.Charting.Title title1 = new System.Windows.Forms.DataVisualization.Charting.Title();
       System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(HeatMapView));
       this.chart = new HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart();
-      this.ColorsPictureBox = new System.Windows.Forms.PictureBox();
-      this.ZeroLabel = new System.Windows.Forms.Label();
-      this.OneLabel = new System.Windows.Forms.Label();
-      this.GrayscalesPictureBox = new System.Windows.Forms.PictureBox();
-      this.grayscaledImagesCheckBox = new System.Windows.Forms.CheckBox();
+      this.colorsPictureBox = new System.Windows.Forms.PictureBox();
+      this.minimumLabel = new System.Windows.Forms.Label();
+      this.maximumLabel = new System.Windows.Forms.Label();
+      this.grayscalesPictureBox = new System.Windows.Forms.PictureBox();
+      this.grayscaleCheckBox = new System.Windows.Forms.CheckBox();
       ((System.ComponentModel.ISupportInitialize)(this.chart)).BeginInit();
-      ((System.ComponentModel.ISupportInitialize)(this.ColorsPictureBox)).BeginInit();
-      ((System.ComponentModel.ISupportInitialize)(this.GrayscalesPictureBox)).BeginInit();
+      ((System.ComponentModel.ISupportInitialize)(this.colorsPictureBox)).BeginInit();
+      ((System.ComponentModel.ISupportInitialize)(this.grayscalesPictureBox)).BeginInit();
       this.SuspendLayout();
       // 
@@ -69,6 +68,6 @@
       chartArea1.AxisX.IntervalAutoMode = System.Windows.Forms.DataVisualization.Charting.IntervalAutoMode.VariableCount;
       chartArea1.AxisX.LabelAutoFitStyle = ((System.Windows.Forms.DataVisualization.Charting.LabelAutoFitStyles)((System.Windows.Forms.DataVisualization.Charting.LabelAutoFitStyles.IncreaseFont | System.Windows.Forms.DataVisualization.Charting.LabelAutoFitStyles.DecreaseFont)));
-      chartArea1.AxisX.Title = "Solution Index";
-      chartArea1.AxisY.Title = "Solution Index";
+      chartArea1.AxisX.Title = "Column Index";
+      chartArea1.AxisY.Title = "Row Index";
       chartArea1.CursorX.IsUserEnabled = true;
       chartArea1.CursorX.IsUserSelectionEnabled = true;
@@ -77,94 +76,90 @@
       chartArea1.Name = "Default";
       this.chart.ChartAreas.Add(chartArea1);
-      legend1.Alignment = System.Drawing.StringAlignment.Center;
-      legend1.Docking = System.Windows.Forms.DataVisualization.Charting.Docking.Top;
-      legend1.Name = "Default";
-      this.chart.Legends.Add(legend1);
       this.chart.Location = new System.Drawing.Point(0, 0);
       this.chart.Name = "chart";
-      this.chart.Size = new System.Drawing.Size(403, 335);
+      this.chart.Size = new System.Drawing.Size(406, 463);
       this.chart.TabIndex = 0;
       this.chart.Text = "chart";
       title1.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
       title1.Name = "Default";
-      title1.Text = "Solution Similarities";
+      title1.Text = "Heat Map";
       this.chart.Titles.Add(title1);
       // 
-      // ColorsPictureBox
+      // colorsPictureBox
       // 
-      this.ColorsPictureBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+      this.colorsPictureBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
                   | System.Windows.Forms.AnchorStyles.Right)));
-      this.ColorsPictureBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
-      this.ColorsPictureBox.Image = ((System.Drawing.Image)(resources.GetObject("ColorsPictureBox.Image")));
-      this.ColorsPictureBox.Location = new System.Drawing.Point(409, 23);
-      this.ColorsPictureBox.Name = "ColorsPictureBox";
-      this.ColorsPictureBox.Size = new System.Drawing.Size(35, 312);
-      this.ColorsPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
-      this.ColorsPictureBox.TabIndex = 11;
-      this.ColorsPictureBox.TabStop = false;
+      this.colorsPictureBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
+      this.colorsPictureBox.Image = ((System.Drawing.Image)(resources.GetObject("colorsPictureBox.Image")));
+      this.colorsPictureBox.Location = new System.Drawing.Point(430, 28);
+      this.colorsPictureBox.Name = "colorsPictureBox";
+      this.colorsPictureBox.Size = new System.Drawing.Size(35, 393);
+      this.colorsPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
+      this.colorsPictureBox.TabIndex = 11;
+      this.colorsPictureBox.TabStop = false;
       // 
-      // ZeroLabel
+      // minimumLabel
       // 
-      this.ZeroLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
-      this.ZeroLabel.AutoSize = true;
-      this.ZeroLabel.BackColor = System.Drawing.Color.Transparent;
-      this.ZeroLabel.Location = new System.Drawing.Point(416, 342);
-      this.ZeroLabel.Name = "ZeroLabel";
-      this.ZeroLabel.Size = new System.Drawing.Size(22, 13);
-      this.ZeroLabel.TabIndex = 14;
-      this.ZeroLabel.Text = "0.0";
+      this.minimumLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+      this.minimumLabel.BackColor = System.Drawing.Color.Transparent;
+      this.minimumLabel.Location = new System.Drawing.Point(412, 424);
+      this.minimumLabel.Name = "minimumLabel";
+      this.minimumLabel.Size = new System.Drawing.Size(73, 19);
+      this.minimumLabel.TabIndex = 2;
+      this.minimumLabel.Text = "0.0";
+      this.minimumLabel.TextAlign = System.Drawing.ContentAlignment.TopCenter;
       // 
-      // OneLabel
+      // maximumLabel
       // 
-      this.OneLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
-      this.OneLabel.AutoSize = true;
-      this.OneLabel.BackColor = System.Drawing.Color.Transparent;
-      this.OneLabel.Location = new System.Drawing.Point(416, 3);
-      this.OneLabel.Name = "OneLabel";
-      this.OneLabel.Size = new System.Drawing.Size(22, 13);
-      this.OneLabel.TabIndex = 13;
-      this.OneLabel.Text = "1.0";
+      this.maximumLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+      this.maximumLabel.BackColor = System.Drawing.Color.Transparent;
+      this.maximumLabel.Location = new System.Drawing.Point(412, 0);
+      this.maximumLabel.Name = "maximumLabel";
+      this.maximumLabel.Size = new System.Drawing.Size(73, 25);
+      this.maximumLabel.TabIndex = 1;
+      this.maximumLabel.Text = "1.0";
+      this.maximumLabel.TextAlign = System.Drawing.ContentAlignment.BottomCenter;
       // 
-      // GrayscalesPictureBox
+      // grayscalesPictureBox
       // 
-      this.GrayscalesPictureBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+      this.grayscalesPictureBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
                   | System.Windows.Forms.AnchorStyles.Right)));
-      this.GrayscalesPictureBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
-      this.GrayscalesPictureBox.Image = ((System.Drawing.Image)(resources.GetObject("GrayscalesPictureBox.Image")));
-      this.GrayscalesPictureBox.Location = new System.Drawing.Point(409, 23);
-      this.GrayscalesPictureBox.Name = "GrayscalesPictureBox";
-      this.GrayscalesPictureBox.Size = new System.Drawing.Size(35, 312);
-      this.GrayscalesPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
-      this.GrayscalesPictureBox.TabIndex = 15;
-      this.GrayscalesPictureBox.TabStop = false;
-      this.GrayscalesPictureBox.Visible = false;
+      this.grayscalesPictureBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
+      this.grayscalesPictureBox.Image = ((System.Drawing.Image)(resources.GetObject("grayscalesPictureBox.Image")));
+      this.grayscalesPictureBox.Location = new System.Drawing.Point(430, 28);
+      this.grayscalesPictureBox.Name = "grayscalesPictureBox";
+      this.grayscalesPictureBox.Size = new System.Drawing.Size(35, 393);
+      this.grayscalesPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
+      this.grayscalesPictureBox.TabIndex = 15;
+      this.grayscalesPictureBox.TabStop = false;
+      this.grayscalesPictureBox.Visible = false;
       // 
-      // grayscaledImagesCheckBox
+      // grayscaleCheckBox
       // 
-      this.grayscaledImagesCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
-      this.grayscaledImagesCheckBox.AutoSize = true;
-      this.grayscaledImagesCheckBox.Location = new System.Drawing.Point(0, 338);
-      this.grayscaledImagesCheckBox.Name = "grayscaledImagesCheckBox";
-      this.grayscaledImagesCheckBox.Size = new System.Drawing.Size(115, 17);
-      this.grayscaledImagesCheckBox.TabIndex = 16;
-      this.grayscaledImagesCheckBox.Text = "Grayscaled images";
-      this.grayscaledImagesCheckBox.UseVisualStyleBackColor = true;
-      this.grayscaledImagesCheckBox.CheckedChanged += new System.EventHandler(this.grayscaledImagesCheckBox_CheckedChanged);
+      this.grayscaleCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+      this.grayscaleCheckBox.AutoSize = true;
+      this.grayscaleCheckBox.Location = new System.Drawing.Point(412, 446);
+      this.grayscaleCheckBox.Name = "grayscaleCheckBox";
+      this.grayscaleCheckBox.Size = new System.Drawing.Size(73, 17);
+      this.grayscaleCheckBox.TabIndex = 3;
+      this.grayscaleCheckBox.Text = "Grayscale";
+      this.grayscaleCheckBox.UseVisualStyleBackColor = true;
+      this.grayscaleCheckBox.CheckedChanged += new System.EventHandler(this.grayscaledImagesCheckBox_CheckedChanged);
       // 
-      // HeatmapView
+      // HeatMapView
       // 
       this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
       this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-      this.Controls.Add(this.grayscaledImagesCheckBox);
-      this.Controls.Add(this.ZeroLabel);
-      this.Controls.Add(this.OneLabel);
-      this.Controls.Add(this.ColorsPictureBox);
+      this.Controls.Add(this.grayscaleCheckBox);
+      this.Controls.Add(this.minimumLabel);
+      this.Controls.Add(this.maximumLabel);
+      this.Controls.Add(this.colorsPictureBox);
       this.Controls.Add(this.chart);
-      this.Controls.Add(this.GrayscalesPictureBox);
-      this.Name = "HeatmapView";
-      this.Size = new System.Drawing.Size(444, 358);
+      this.Controls.Add(this.grayscalesPictureBox);
+      this.Name = "HeatMapView";
+      this.Size = new System.Drawing.Size(485, 463);
       ((System.ComponentModel.ISupportInitialize)(this.chart)).EndInit();
-      ((System.ComponentModel.ISupportInitialize)(this.ColorsPictureBox)).EndInit();
-      ((System.ComponentModel.ISupportInitialize)(this.GrayscalesPictureBox)).EndInit();
+      ((System.ComponentModel.ISupportInitialize)(this.colorsPictureBox)).EndInit();
+      ((System.ComponentModel.ISupportInitialize)(this.grayscalesPictureBox)).EndInit();
       this.ResumeLayout(false);
       this.PerformLayout();
@@ -174,10 +169,10 @@
     #endregion
 
-    private HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart chart;
-    private System.Windows.Forms.PictureBox ColorsPictureBox;
-    private System.Windows.Forms.Label ZeroLabel;
-    private System.Windows.Forms.Label OneLabel;
-    private System.Windows.Forms.PictureBox GrayscalesPictureBox;
-    private System.Windows.Forms.CheckBox grayscaledImagesCheckBox;
+    protected HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart chart;
+    protected System.Windows.Forms.PictureBox colorsPictureBox;
+    protected System.Windows.Forms.Label minimumLabel;
+    protected System.Windows.Forms.Label maximumLabel;
+    protected System.Windows.Forms.PictureBox grayscalesPictureBox;
+    protected System.Windows.Forms.CheckBox grayscaleCheckBox;
   }
 }
Index: /trunk/sources/HeuristicLab.Analysis.Views/3.3/HeatMapView.cs
===================================================================
--- /trunk/sources/HeuristicLab.Analysis.Views/3.3/HeatMapView.cs	(revision 4738)
+++ /trunk/sources/HeuristicLab.Analysis.Views/3.3/HeatMapView.cs	(revision 4739)
@@ -31,33 +31,24 @@
   [Content(typeof(HeatMap), true)]
   public partial class HeatMapView : ItemView {
+    protected static Color[] colors = new Color[256];
+    protected static Color[] grayscaleColors = new Color[256];
 
-    private static Color[] Colors;
-    private static int ColorsCount = 500;
-    private static Color[] GrayscaleColors = new Color[256];
-
-    #region InitializeColors
+    #region Initialize Colors
     static HeatMapView() {
-      int stepWidth = (255 * 6) / ColorsCount;
-      Color[] colors = new Color[ColorsCount];
+      int stepWidth = (256 * 4) / colors.Length;
       int currentValue;
       int currentClass;
-      for (int i = 0; i < ColorsCount; i++) {
-        currentValue = (i * stepWidth) % 255;
-        currentClass = (i * stepWidth) / 255;
+      for (int i = 0; i < colors.Length; i++) {
+        currentValue = (i * stepWidth) % 256;
+        currentClass = (i * stepWidth) / 256;
         switch (currentClass) {
-          case 0: { colors[i] = Color.FromArgb(255, currentValue, 0); break; }
-          case 1: { colors[i] = Color.FromArgb(255 - currentValue, 255, 0); break; }
-          case 2: { colors[i] = Color.FromArgb(0, 255, currentValue); break; }
-          case 3: { colors[i] = Color.FromArgb(0, 255 - currentValue, 255); break; }
-          case 4: { colors[i] = Color.FromArgb(currentValue, 0, 255); break; }
-          case 5: { colors[i] = Color.FromArgb(255, 0, 255 - currentValue); break; }
+          case 0: { colors[i] = Color.FromArgb(0, currentValue, 255); break; }        // blue -> cyan
+          case 1: { colors[i] = Color.FromArgb(0, 255, 255 - currentValue); break; }  // cyan -> green
+          case 2: { colors[i] = Color.FromArgb(currentValue, 255, 0); break; }        // green -> yellow
+          case 3: { colors[i] = Color.FromArgb(255, 255 - currentValue, 0); break; }  // yellow -> red
         }
       }
-      int n = (int)(ColorsCount * 0.7);
-      Colors = new Color[n];
-      for (int i = 0; i < n; i++)
-        Colors[i] = colors[i];
       for (int i = 0; i < 256; i++)
-        GrayscaleColors[i] = Color.FromArgb(i, i, i);
+        grayscaleColors[i] = Color.FromArgb(255 - i, 255 - i, 255 - i);  // white -> black
     }
     #endregion
@@ -73,14 +64,39 @@
     }
 
+    protected override void DeregisterContentEvents() {
+      Content.TitleChanged -= new EventHandler(Content_TitleChanged);
+      Content.MinimumChanged -= new EventHandler(Content_MinimumChanged);
+      Content.MaximumChanged -= new EventHandler(Content_MaximumChanged);
+      base.DeregisterContentEvents();
+    }
+    protected override void RegisterContentEvents() {
+      base.RegisterContentEvents();
+      Content.TitleChanged += new EventHandler(Content_TitleChanged);
+      Content.MinimumChanged += new EventHandler(Content_MinimumChanged);
+      Content.MaximumChanged += new EventHandler(Content_MaximumChanged);
+    }
+
     protected override void OnContentChanged() {
       base.OnContentChanged();
       if (Content == null) {
         chart.Series.Clear();
+        chart.Titles[0].Text = "Heat Map";
+        minimumLabel.Text = "0.0";
+        maximumLabel.Text = "1.0";
       } else {
-        UpdateChart();
+        chart.Titles[0].Text = Content.Title;
+        minimumLabel.Text = Content.Minimum.ToString();
+        maximumLabel.Text = Content.Maximum.ToString();
+        UpdatePoints();
       }
     }
 
-    private void UpdateChart() {
+    protected override void SetEnabledStateOfControls() {
+      base.SetEnabledStateOfControls();
+      chart.Enabled = Content != null;
+      grayscaleCheckBox.Enabled = Content != null;
+    }
+
+    protected virtual void UpdatePoints() {
       chart.Series.Clear();
       Series series = new Series();
@@ -89,42 +105,65 @@
       series.YValueType = ChartValueType.Int32;
       series.YAxisType = AxisType.Primary;
-      for (int i = 0; i < Content.Rows; i++)
-        for (int j = 0; j < Content.Columns; j++)
-          series.Points.Add(CreateDataPoint(i, j, Content[i, j]));
+      for (int i = 1; i < Content.Rows + 1; i++)
+        for (int j = 1; j < Content.Columns + 1; j++)
+          series.Points.Add(CreateDataPoint(j, i, Content[i - 1, j - 1]));
+      chart.ChartAreas[0].AxisX.Minimum = 0;
+      chart.ChartAreas[0].AxisX.Maximum = Content.Columns + 1;
       chart.ChartAreas[0].AxisY.Minimum = 0;
-      chart.ChartAreas[0].AxisY.Maximum = Content.Rows;
+      chart.ChartAreas[0].AxisY.Maximum = Content.Rows + 1;
       chart.Series.Add(series);
-      chart.Legends.Clear();
     }
 
-    private DataPoint CreateDataPoint(int index1, int index2, double value) {
-      bool grayScaleModus = grayscaledImagesCheckBox.Checked;
-      int n = grayScaleModus ? GrayscaleColors.Length : Colors.Length;
-      int colorIndex = (int)((n - 1) * value);
-      if (colorIndex >= n) colorIndex = n - 1;
-      if (colorIndex < 0) colorIndex = 0;
-      // invert so that red is 1, blue 0 / black is 1, white 0
-      colorIndex = n - colorIndex - 1;
-      Color color = grayScaleModus ? GrayscaleColors[colorIndex] : Colors[colorIndex];
-
+    protected virtual DataPoint CreateDataPoint(int index1, int index2, double value) {
       DataPoint p = new DataPoint(index1, index2);
-      p.Color = color;
+      p.Color = GetDataPointColor(value, Content.Minimum, Content.Maximum, grayscaleCheckBox.Checked);
       p.MarkerStyle = MarkerStyle.Square;
-      p.ToolTip = string.Format("Solution {0} vs. solution {1}: {2}",
-                                index1, index2, value);
+      //p.MarkerSize = 10;
+      //string nl = Environment.NewLine;
+      //p.ToolTip = string.Format("Row: {0}{3}Column: {1}{3}Value: {2}", index2, index1, value, nl);
       return p;
     }
 
-    #region Chart Events
-
-    private void grayscaledImagesCheckBox_CheckedChanged(object sender, EventArgs e) {
-      GrayscalesPictureBox.Visible = grayscaledImagesCheckBox.Checked;
-      ColorsPictureBox.Visible = !grayscaledImagesCheckBox.Checked;
-      UpdateChart();
+    protected virtual Color GetDataPointColor(double value, double min, double max, bool grayscale) {
+      int count = grayscale ? grayscaleColors.Length : colors.Length;
+      int index = (int)((count - 1) * (value - min) / (max - min));
+      if (index >= count) index = count - 1;
+      if (index < 0) index = 0;
+      return grayscale ? grayscaleColors[index] : colors[index];
     }
 
+    #region Content Events
+    protected virtual void Content_TitleChanged(object sender, EventArgs e) {
+      if (InvokeRequired)
+        Invoke(new EventHandler(Content_TitleChanged), sender, e);
+      else {
+        chart.Titles[0].Text = Content.Title;
+      }
+    }
+    protected virtual void Content_MinimumChanged(object sender, EventArgs e) {
+      if (InvokeRequired)
+        Invoke(new EventHandler(Content_MinimumChanged), sender, e);
+      else {
+        minimumLabel.Text = Content.Minimum.ToString();
+        UpdatePoints();
+      }
+    }
+    protected virtual void Content_MaximumChanged(object sender, EventArgs e) {
+      if (InvokeRequired)
+        Invoke(new EventHandler(Content_MaximumChanged), sender, e);
+      else {
+        maximumLabel.Text = Content.Maximum.ToString();
+        UpdatePoints();
+      }
+    }
     #endregion
 
+    #region Control Events
+    protected virtual void grayscaledImagesCheckBox_CheckedChanged(object sender, EventArgs e) {
+      grayscalesPictureBox.Visible = grayscaleCheckBox.Checked;
+      colorsPictureBox.Visible = !grayscaleCheckBox.Checked;
+      UpdatePoints();
+    }
+    #endregion
   }
-
 }
Index: /trunk/sources/HeuristicLab.Analysis.Views/3.3/HeatMapView.resx
===================================================================
--- /trunk/sources/HeuristicLab.Analysis.Views/3.3/HeatMapView.resx	(revision 4738)
+++ /trunk/sources/HeuristicLab.Analysis.Views/3.3/HeatMapView.resx	(revision 4739)
@@ -119,5 +119,5 @@
   </resheader>
   <assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
-  <data name="ColorsPictureBox.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+  <data name="colorsPictureBox.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
     <value>
         Qk0S0gAAAAAAADYAAAAoAAAAMQAAAGsBAAABABgAAAAAAAAAAADEDgAAxA4AAAAAAAAAAAAA/wAe/wAe
@@ -1020,5 +1020,5 @@
 </value>
   </data>
-  <data name="GrayscalesPictureBox.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+  <data name="grayscalesPictureBox.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
     <value>
         Qk0S0gAAAAAAADYAAAAoAAAAMQAAAGsBAAABABgAAAAAAAAAAADEDgAAxA4AAAAAAAAAAAAA////////
Index: /trunk/sources/HeuristicLab.Analysis/3.3/HeatMap.cs
===================================================================
--- /trunk/sources/HeuristicLab.Analysis/3.3/HeatMap.cs	(revision 4738)
+++ /trunk/sources/HeuristicLab.Analysis/3.3/HeatMap.cs	(revision 4739)
@@ -20,5 +20,5 @@
 #endregion
 
-using System.Collections.Generic;
+using System;
 using System.Drawing;
 using HeuristicLab.Common;
@@ -35,14 +35,100 @@
     }
 
+    private string title;
+    public string Title {
+      get { return title; }
+      set {
+        if (!(title.Equals(value) || (value == null) && (title == string.Empty))) {
+          title = value == null ? string.Empty : value;
+          OnTitleChanged();
+        }
+      }
+    }
+    private double minimum;
+    public double Minimum {
+      get { return minimum; }
+      set {
+        if (minimum != value) {
+          minimum = value;
+          if (minimum >= maximum) Maximum = minimum + 1.0;
+          OnMinimumChanged();
+        }
+      }
+    }
+    private double maximum;
+    public double Maximum {
+      get { return maximum; }
+      set {
+        if (maximum != value) {
+          maximum = value;
+          if (maximum <= minimum) Minimum = maximum - 1.0;
+          OnMaximumChanged();
+        }
+      }
+    }
+
+    #region Storable Properties
+    [Storable(Name = "Title")]
+    private string StorableTitle {
+      get { return title; }
+      set { title = value; }
+    }
+    [Storable(Name = "Minimum")]
+    private double StorableMinimum {
+      get { return minimum; }
+      set { minimum = value; }
+    }
+    [Storable(Name = "Maximum")]
+    private double StorableMaximum {
+      get { return maximum; }
+      set { maximum = value; }
+    }
+    #endregion
+
     [StorableConstructor]
     protected HeatMap(bool deserializing) : base(deserializing) { }
-    protected HeatMap(HeatMap original, Cloner cloner) : base(original, cloner) { }
-    public HeatMap() : base() { }
-    public HeatMap(int rows, int columns) : base(rows, columns) { }
-    public HeatMap(int rows, int columns, IEnumerable<string> columnNames) : base(rows, columns, columnNames) { }
-    public HeatMap(int rows, int columns, IEnumerable<string> columnNames, IEnumerable<string> rowNames) : base(rows, columns, columnNames, rowNames) { }
-    public HeatMap(double[,] elements) : base(elements) { }
-    public HeatMap(double[,] elements, IEnumerable<string> columnNames) : base(elements, columnNames) { }
-    public HeatMap(double[,] elements, IEnumerable<string> columnNames, IEnumerable<string> rowNames) : base(elements, columnNames, rowNames) { }
+    protected HeatMap(HeatMap original, Cloner cloner)
+      : base(original, cloner) {
+      this.title = original.title;
+      this.minimum = original.minimum;
+      this.maximum = original.maximum;
+    }
+    public HeatMap()
+      : base() {
+      this.title = "Heat Map";
+      this.minimum = 0.0;
+      this.maximum = 1.0;
+    }
+    public HeatMap(int rows, int columns)
+      : base(rows, columns) {
+      this.title = "Heat Map";
+      this.minimum = 0.0;
+      this.maximum = 1.0;
+    }
+    public HeatMap(int rows, int columns, string title)
+      : base(rows, columns) {
+      this.title = title == null ? string.Empty : title;
+      this.minimum = 0.0;
+      this.maximum = 1.0;
+    }
+    public HeatMap(double[,] elements)
+      : base(elements) {
+      this.title = "Heat Map";
+      this.minimum = 0.0;
+      this.maximum = 1.0;
+    }
+    public HeatMap(double[,] elements, string title)
+      : base(elements) {
+      this.title = title == null ? string.Empty : title;
+      this.minimum = 0.0;
+      this.maximum = 1.0;
+    }
+    public HeatMap(double[,] elements, string title, double minimum, double maximum)
+      : base(elements) {
+      this.title = title == null ? string.Empty : title;
+      if (minimum >= maximum) throw new ArgumentException("Minimum is larger than or equal to maximum");
+      this.minimum = minimum;
+      this.maximum = maximum;
+    }
 
     public override IDeepCloneable Clone(Cloner cloner) {
@@ -51,5 +137,21 @@
 
     public override string ToString() {
-      return ItemName;
+      return Title;
+    }
+
+    public event EventHandler TitleChanged;
+    protected virtual void OnTitleChanged() {
+      var handler = TitleChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler MinimumChanged;
+    protected virtual void OnMinimumChanged() {
+      var handler = MinimumChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler MaximumChanged;
+    protected virtual void OnMaximumChanged() {
+      var handler = MaximumChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
     }
   }
Index: /trunk/sources/HeuristicLab.Analysis/3.3/PopulationDiversityAnalyzer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Analysis/3.3/PopulationDiversityAnalyzer.cs	(revision 4738)
+++ /trunk/sources/HeuristicLab.Analysis/3.3/PopulationDiversityAnalyzer.cs	(revision 4739)
@@ -87,136 +87,127 @@
         ItemArray<DoubleValue> qualities = QualityParameter.ActualValue;
         bool storeHistory = StoreHistoryParameter.Value.Value;
-
-        // sort solutions by quality
-        T[] sortedSolutions = null;
-        if (max)
-          sortedSolutions = solutions.Select((x, index) => new { Solution = x, Quality = qualities[index] }).OrderByDescending(x => x.Quality).Select(x => x.Solution).ToArray();
-        else
-          sortedSolutions = solutions.Select((x, index) => new { Solution = x, Quality = qualities[index] }).OrderBy(x => x.Quality).Select(x => x.Solution).ToArray();
-
-        // calculate solution similarities
-        double[,] similarities = CalculateSimilarities(sortedSolutions);
-
-        // calculate minimum, average and maximum similarities
-        double similarity;
-        int count = sortedSolutions.Length;
-        double[] minSimilarities = new double[sortedSolutions.Length];
-        double[] avgSimilarities = new double[sortedSolutions.Length];
-        double[] maxSimilarities = new double[sortedSolutions.Length];
-        double avgSimilarity = 0;
-        for (int i = 0; i < count; i++) {
-          minSimilarities[i] = 1;
-          avgSimilarities[i] = 0;
-          maxSimilarities[i] = 0;
-          for (int j = 0; j < count; j++) {
-            if (i != j) {
-              similarity = similarities[i, j];
-              avgSimilarity += similarity;
-              if (minSimilarities[i] > similarity) minSimilarities[i] = similarity;
-              avgSimilarities[i] += similarity;
-              if (maxSimilarities[i] < similarity) maxSimilarities[i] = similarity;
+        int count = solutions.Length;
+
+        if (count > 1) {
+          // sort solutions by quality
+          T[] sortedSolutions = null;
+          if (max)
+            sortedSolutions = solutions.Select((x, index) => new { Solution = x, Quality = qualities[index] }).OrderByDescending(x => x.Quality).Select(x => x.Solution).ToArray();
+          else
+            sortedSolutions = solutions.Select((x, index) => new { Solution = x, Quality = qualities[index] }).OrderBy(x => x.Quality).Select(x => x.Solution).ToArray();
+
+          // calculate solution similarities
+          double[,] similarities = CalculateSimilarities(sortedSolutions);
+
+          // calculate minimum, average and maximum similarities
+          double similarity;
+          double[] minSimilarities = new double[sortedSolutions.Length];
+          double[] avgSimilarities = new double[sortedSolutions.Length];
+          double[] maxSimilarities = new double[sortedSolutions.Length];
+          for (int i = 0; i < count; i++) {
+            minSimilarities[i] = 1;
+            avgSimilarities[i] = 0;
+            maxSimilarities[i] = 0;
+            for (int j = 0; j < count; j++) {
+              if (i != j) {
+                similarity = similarities[i, j];
+                if (minSimilarities[i] > similarity) minSimilarities[i] = similarity;
+                avgSimilarities[i] += similarity;
+                if (maxSimilarities[i] < similarity) maxSimilarities[i] = similarity;
+              }
             }
-          }
-          avgSimilarities[i] = avgSimilarities[i] / (count - 1);
-        }
-        double avgMinSimilarity = minSimilarities.Average();
-        double avgAvgSimilarity = avgSimilarities.Average();
-        double avgMaxSimilarity = maxSimilarities.Average();
-        avgSimilarity = avgSimilarity / (count * count - count);
-
-        // fetch results collection
-        ResultCollection results;
-        if (!ResultsParameter.ActualValue.ContainsKey("Population Diversity Analysis Results")) {
-          results = new ResultCollection();
-          ResultsParameter.ActualValue.Add(new Result("Population Diversity Analysis Results", results));
-        } else {
-          results = (ResultCollection)ResultsParameter.ActualValue["Population Diversity Analysis Results"].Value;
-        }
-
-        // store similarities
-        HeatMap similaritiesHeatMap = new HeatMap(similarities);
-        if (!results.ContainsKey("Solution Similarities"))
-          results.Add(new Result("Solution Similarities", similaritiesHeatMap));
-        else
-          results["Solution Similarities"].Value = similaritiesHeatMap;
-
-        // store similarities history
-        if (storeHistory) {
-          if (!results.ContainsKey("Solution Similarities History")) {
-            HeatMapHistory history = new HeatMapHistory();
-            history.Add(similaritiesHeatMap);
-            results.Add(new Result("Solution Similarities History", history));
+            avgSimilarities[i] = avgSimilarities[i] / (count - 1);
+          }
+          double avgMinSimilarity = minSimilarities.Average();
+          double avgAvgSimilarity = avgSimilarities.Average();
+          double avgMaxSimilarity = maxSimilarities.Average();
+
+          // fetch results collection
+          ResultCollection results;
+          if (!ResultsParameter.ActualValue.ContainsKey("Population Diversity Analysis Results")) {
+            results = new ResultCollection();
+            ResultsParameter.ActualValue.Add(new Result("Population Diversity Analysis Results", results));
           } else {
-            ((HeatMapHistory)results["Solution Similarities History"].Value).Add(similaritiesHeatMap);
-          }
-        }
-
-        // store average similarity
-        if (!results.ContainsKey("Average Population Similarity"))
-          results.Add(new Result("Average Population Similarity", new DoubleValue(avgSimilarity)));
-        else
-          ((DoubleValue)results["Average Population Similarity"].Value).Value = avgSimilarity;
-
-        // store average minimum, average and maximum similarity
-        if (!results.ContainsKey("Average Minimum Solution Similarity"))
-          results.Add(new Result("Average Minimum Solution Similarity", new DoubleValue(avgMinSimilarity)));
-        else
-          ((DoubleValue)results["Average Minimum Solution Similarity"].Value).Value = avgMinSimilarity;
-
-        if (!results.ContainsKey("Average Average Solution Similarity"))
-          results.Add(new Result("Average Average Solution Similarity", new DoubleValue(avgAvgSimilarity)));
-        else
-          ((DoubleValue)results["Average Average Solution Similarity"].Value).Value = avgAvgSimilarity;
-
-        if (!results.ContainsKey("Average Maximum Solution Similarity"))
-          results.Add(new Result("Average Maximum Solution Similarity", new DoubleValue(avgMaxSimilarity)));
-        else
-          ((DoubleValue)results["Average Maximum Solution Similarity"].Value).Value = avgMaxSimilarity;
-
-        // store population similarity data table
-        DataTable similarityDataTable;
-        if (!results.ContainsKey("Average Solution Similarity")) {
-          similarityDataTable = new DataTable("Average Solution Similarity");
-          results.Add(new Result("Average Solution Similarity", similarityDataTable));
-          DataRowVisualProperties visualProperties = new DataRowVisualProperties();
-          visualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Line;
-          visualProperties.StartIndexZero = true;
-          similarityDataTable.Rows.Add(new DataRow("Average Population Similarity", null, visualProperties));
-          similarityDataTable.Rows.Add(new DataRow("Average Minimum Solution Similarity", null, visualProperties));
-          similarityDataTable.Rows.Add(new DataRow("Average Average Solution Similarity", null, visualProperties));
-          similarityDataTable.Rows.Add(new DataRow("Average Maximum Solution Similarity", null, visualProperties));
-        } else {
-          similarityDataTable = (DataTable)results["Average Solution Similarity"].Value;
-        }
-        similarityDataTable.Rows["Average Population Similarity"].Values.Add(avgSimilarity);
-        similarityDataTable.Rows["Average Minimum Solution Similarity"].Values.Add(avgMinSimilarity);
-        similarityDataTable.Rows["Average Average Solution Similarity"].Values.Add(avgAvgSimilarity);
-        similarityDataTable.Rows["Average Maximum Solution Similarity"].Values.Add(avgMaxSimilarity);
-
-        // store maximum similarities
-        DataTable minAvgMaxSimilaritiesDataTable = new DataTable("Minimum/Average/Maximum Solution Similarities");
-        minAvgMaxSimilaritiesDataTable.Rows.Add(new DataRow("Minimum Solution Similarity"));
-        minAvgMaxSimilaritiesDataTable.Rows["Minimum Solution Similarity"].VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Columns;
-        minAvgMaxSimilaritiesDataTable.Rows["Minimum Solution Similarity"].Values.AddRange(minSimilarities);
-        minAvgMaxSimilaritiesDataTable.Rows.Add(new DataRow("Average Solution Similarity"));
-        minAvgMaxSimilaritiesDataTable.Rows["Average Solution Similarity"].VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Columns;
-        minAvgMaxSimilaritiesDataTable.Rows["Average Solution Similarity"].Values.AddRange(avgSimilarities);
-        minAvgMaxSimilaritiesDataTable.Rows.Add(new DataRow("Maximum Solution Similarity"));
-        minAvgMaxSimilaritiesDataTable.Rows["Maximum Solution Similarity"].VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Columns;
-        minAvgMaxSimilaritiesDataTable.Rows["Maximum Solution Similarity"].Values.AddRange(maxSimilarities);
-        if (!results.ContainsKey("Minimum/Average/Maximum Solution Similarities")) {
-          results.Add(new Result("Minimum/Average/Maximum Solution Similarities", minAvgMaxSimilaritiesDataTable));
-        } else {
-          results["Minimum/Average/Maximum Solution Similarities"].Value = minAvgMaxSimilaritiesDataTable;
-        }
-
-        // store maximum similarities history
-        if (storeHistory) {
-          if (!results.ContainsKey("Minimum/Average/Maximum Solution Similarities History")) {
-            DataTableHistory history = new DataTableHistory();
-            history.Add(minAvgMaxSimilaritiesDataTable);
-            results.Add(new Result("Minimum/Average/Maximum Solution Similarities History", history));
+            results = (ResultCollection)ResultsParameter.ActualValue["Population Diversity Analysis Results"].Value;
+          }
+
+          // store similarities
+          HeatMap similaritiesHeatMap = new HeatMap(similarities, "Solution Similarities", 0.0, 1.0);
+          if (!results.ContainsKey("Solution Similarities"))
+            results.Add(new Result("Solution Similarities", similaritiesHeatMap));
+          else
+            results["Solution Similarities"].Value = similaritiesHeatMap;
+
+          // store similarities history
+          if (storeHistory) {
+            if (!results.ContainsKey("Solution Similarities History")) {
+              HeatMapHistory history = new HeatMapHistory();
+              history.Add(similaritiesHeatMap);
+              results.Add(new Result("Solution Similarities History", history));
+            } else {
+              ((HeatMapHistory)results["Solution Similarities History"].Value).Add(similaritiesHeatMap);
+            }
+          }
+
+          // store average minimum, average and maximum similarity
+          if (!results.ContainsKey("Average Minimum Solution Similarity"))
+            results.Add(new Result("Average Minimum Solution Similarity", new DoubleValue(avgMinSimilarity)));
+          else
+            ((DoubleValue)results["Average Minimum Solution Similarity"].Value).Value = avgMinSimilarity;
+
+          if (!results.ContainsKey("Average Average Solution Similarity"))
+            results.Add(new Result("Average Average Solution Similarity", new DoubleValue(avgAvgSimilarity)));
+          else
+            ((DoubleValue)results["Average Average Solution Similarity"].Value).Value = avgAvgSimilarity;
+
+          if (!results.ContainsKey("Average Maximum Solution Similarity"))
+            results.Add(new Result("Average Maximum Solution Similarity", new DoubleValue(avgMaxSimilarity)));
+          else
+            ((DoubleValue)results["Average Maximum Solution Similarity"].Value).Value = avgMaxSimilarity;
+
+          // store average minimum, average and maximum solution similarity data table
+          DataTable minAvgMaxSimilarityDataTable;
+          if (!results.ContainsKey("Average Minimum/Average/Maximum Solution Similarity")) {
+            minAvgMaxSimilarityDataTable = new DataTable("Average Minimum/Average/Maximum Solution Similarity");
+            results.Add(new Result("Average Minimum/Average/Maximum Solution Similarity", minAvgMaxSimilarityDataTable));
+            DataRowVisualProperties visualProperties = new DataRowVisualProperties();
+            visualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Line;
+            visualProperties.StartIndexZero = true;
+            minAvgMaxSimilarityDataTable.Rows.Add(new DataRow("Average Minimum Solution Similarity", null, visualProperties));
+            minAvgMaxSimilarityDataTable.Rows.Add(new DataRow("Average Average Solution Similarity", null, visualProperties));
+            minAvgMaxSimilarityDataTable.Rows.Add(new DataRow("Average Maximum Solution Similarity", null, visualProperties));
           } else {
-            ((DataTableHistory)results["Minimum/Average/Maximum Solution Similarities History"].Value).Add(minAvgMaxSimilaritiesDataTable);
+            minAvgMaxSimilarityDataTable = (DataTable)results["Average Minimum/Average/Maximum Solution Similarity"].Value;
+          }
+          minAvgMaxSimilarityDataTable.Rows["Average Minimum Solution Similarity"].Values.Add(avgMinSimilarity);
+          minAvgMaxSimilarityDataTable.Rows["Average Average Solution Similarity"].Values.Add(avgAvgSimilarity);
+          minAvgMaxSimilarityDataTable.Rows["Average Maximum Solution Similarity"].Values.Add(avgMaxSimilarity);
+
+          // store minimum, average, maximum similarities data table
+          DataTable minAvgMaxSimilaritiesDataTable = new DataTable("Minimum/Average/Maximum Solution Similarities");
+          minAvgMaxSimilaritiesDataTable.Rows.Add(new DataRow("Minimum Solution Similarity"));
+          minAvgMaxSimilaritiesDataTable.Rows["Minimum Solution Similarity"].VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Columns;
+          minAvgMaxSimilaritiesDataTable.Rows["Minimum Solution Similarity"].Values.AddRange(minSimilarities);
+          minAvgMaxSimilaritiesDataTable.Rows.Add(new DataRow("Average Solution Similarity"));
+          minAvgMaxSimilaritiesDataTable.Rows["Average Solution Similarity"].VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Columns;
+          minAvgMaxSimilaritiesDataTable.Rows["Average Solution Similarity"].Values.AddRange(avgSimilarities);
+          minAvgMaxSimilaritiesDataTable.Rows.Add(new DataRow("Maximum Solution Similarity"));
+          minAvgMaxSimilaritiesDataTable.Rows["Maximum Solution Similarity"].VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Columns;
+          minAvgMaxSimilaritiesDataTable.Rows["Maximum Solution Similarity"].Values.AddRange(maxSimilarities);
+          if (!results.ContainsKey("Minimum/Average/Maximum Solution Similarities")) {
+            results.Add(new Result("Minimum/Average/Maximum Solution Similarities", minAvgMaxSimilaritiesDataTable));
+          } else {
+            results["Minimum/Average/Maximum Solution Similarities"].Value = minAvgMaxSimilaritiesDataTable;
+          }
+
+          // store minimum, average, maximum similarities history
+          if (storeHistory) {
+            if (!results.ContainsKey("Minimum/Average/Maximum Solution Similarities History")) {
+              DataTableHistory history = new DataTableHistory();
+              history.Add(minAvgMaxSimilaritiesDataTable);
+              results.Add(new Result("Minimum/Average/Maximum Solution Similarities History", history));
+            } else {
+              ((DataTableHistory)results["Minimum/Average/Maximum Solution Similarities History"].Value).Add(minAvgMaxSimilaritiesDataTable);
+            }
           }
         }
Index: /trunk/sources/HeuristicLab.Visualization.ChartControlsExtensions/3.3/EnhancedChart.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Visualization.ChartControlsExtensions/3.3/EnhancedChart.Designer.cs	(revision 4738)
+++ /trunk/sources/HeuristicLab.Visualization.ChartControlsExtensions/3.3/EnhancedChart.Designer.cs	(revision 4739)
@@ -78,5 +78,5 @@
       // saveFileDialog
       // 
-      this.saveFileDialog.Filter = "\"Bitmap (*.bmp)|*.bmp|JPEG (*.jpg)|*.jpg|EMF (*.emf)|*.emf|PNG (*.png)|*.png|GIF " +
+      this.saveFileDialog.Filter = "Bitmap (*.bmp)|*.bmp|JPEG (*.jpg)|*.jpg|EMF (*.emf)|*.emf|PNG (*.png)|*.png|GIF " +
           "(*.gif)|*.gif|TIFF (*.tif)|*.tif\"";
       this.saveFileDialog.FilterIndex = 2;
