Index: /branches/PerformanceComparison/HeuristicLab.Analysis.Views/3.3/IndexedDataTableView.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Analysis.Views/3.3/IndexedDataTableView.cs	(revision 12864)
+++ /branches/PerformanceComparison/HeuristicLab.Analysis.Views/3.3/IndexedDataTableView.cs	(revision 12865)
@@ -36,9 +36,5 @@
     protected List<Series> invisibleSeries;
     protected Dictionary<IObservableList<Tuple<T, double>>, IndexedDataRow<T>> valuesRowsTable;
-    /// <summary>
-    /// Gets or sets the variable to represent visually.
-    /// </summary>
-    /// <remarks>Uses property <see cref="ViewBase.Item"/> of base class <see cref="ViewBase"/>.
-    /// No own data storage present.</remarks>
+
     public new IndexedDataTable<T> Content {
       get { return (IndexedDataTable<T>)base.Content; }
@@ -46,7 +42,4 @@
     }
 
-    /// <summary>
-    /// Initializes a new instance of <see cref="VariableView"/> with caption "Variable".
-    /// </summary>
     public IndexedDataTableView() {
       InitializeComponent();
@@ -59,8 +52,4 @@
 
     #region Event Handler Registration
-    /// <summary>
-    /// Removes the eventhandlers from the underlying <see cref="Variable"/>.
-    /// </summary>
-    /// <remarks>Calls <see cref="ViewBase.RemoveItemEvents"/> of base class <see cref="ViewBase"/>.</remarks>
     protected override void DeregisterContentEvents() {
       foreach (var row in Content.Rows)
@@ -74,8 +63,4 @@
     }
 
-    /// <summary>
-    /// Adds eventhandlers to the underlying <see cref="Variable"/>.
-    /// </summary>
-    /// <remarks>Calls <see cref="ViewBase.AddItemEvents"/> of base class <see cref="ViewBase"/>.</remarks>
     protected override void RegisterContentEvents() {
       base.RegisterContentEvents();
@@ -177,4 +162,13 @@
       else series.Color = Color.Empty;
       series.IsVisibleInLegend = row.VisualProperties.IsVisibleInLegend;
+
+      series.SmartLabelStyle.Enabled = true;
+      series.SmartLabelStyle.AllowOutsidePlotArea = LabelOutsidePlotAreaStyle.Yes;
+      series.SmartLabelStyle.CalloutLineAnchorCapStyle = LineAnchorCapStyle.None;
+      series.SmartLabelStyle.CalloutLineColor = series.Color;
+      series.SmartLabelStyle.CalloutLineWidth = 2;
+      series.SmartLabelStyle.CalloutStyle = LabelCalloutStyle.Underlined;
+      series.SmartLabelStyle.IsOverlappedHidden = false;
+      series.SmartLabelStyle.MaxMovingDistance = 200;
 
       switch (row.VisualProperties.ChartType) {
@@ -564,6 +558,12 @@
       for (int i = 0; i < row.Values.Count; i++) {
         var value = row.Values[i];
-        DataPoint point = new DataPoint();
+        var point = new DataPoint();
         point.SetValueXY(value.Item1, value.Item2);
+        if (i == row.Values.Count - 1) {
+          point.Label = series.Name;
+          point.MarkerStyle = MarkerStyle.Cross;
+          point.MarkerSize = 15;
+          point.MarkerBorderWidth = 1;
+        }
         series.Points.Add(point);
       }
Index: /branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.cs	(revision 12864)
+++ /branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.cs	(revision 12865)
@@ -526,4 +526,15 @@
       var lineStyleCount = 0;
 
+      var maximization = IsMaximization();
+      var targetsPerProblem = (from r in Content
+                               let pd = new ProblemDescription(r).ToString()
+                               let target = r.Parameters.ContainsKey("BestKnownQuality")
+                                && r.Parameters["BestKnownQuality"] is DoubleValue
+                                  ? ((DoubleValue)r.Parameters["BestKnownQuality"]).Value
+                                  : ((IndexedDataTable<double>)r.Results[(string)dataTableComboBox.SelectedItem]).Rows.First().Values.Last().Item2
+                               group target by pd into g
+                               select new { Problem = g.Key, Target = maximization ? g.Max() : g.Min() })
+                              .ToDictionary(x => x.Problem, x => x.Target);
+
       foreach (var group in groupedRuns) {
         var hits = new Dictionary<string, SortedList<double, double>>();
@@ -534,7 +545,7 @@
 
             if (eachOrAllBudgetsCheckBox.Checked) {
-              CalculateHitsForEachBudget(hits, resultsTable.Rows.First(), group.Value.Count, group.Key, problem.Value.Item2.Count);
+              CalculateHitsForEachBudget(hits, resultsTable.Rows.First(), maximization, group.Value.Count, group.Key, problem.Value.Item2.Count, targetsPerProblem[problem.Key]);
             } else {
-              CalculateHitsForAllBudgets(hits, resultsTable.Rows.First(), group.Value.Count, group.Key, problem.Value.Item2.Count);
+              CalculateHitsForAllBudgets(hits, resultsTable.Rows.First(), maximization, group.Value.Count, group.Key, problem.Value.Item2.Count, targetsPerProblem[problem.Key]);
             }
           }
@@ -563,5 +574,5 @@
       }
 
-      byCostDataTable.VisualProperties.XAxisTitle = "Targets";
+      byCostDataTable.VisualProperties.XAxisTitle = "Targets to Best-Known Ratio";
       byCostDataTable.VisualProperties.XAxisLogScale = byCostDataTable.Rows.Count > 0 && budgetLogScalingCheckBox.Checked;
     }
@@ -588,5 +599,5 @@
     }
 
-    private void CalculateHitsForEachBudget(Dictionary<string, SortedList<double, double>> hits, IndexedDataRow<double> row, int groupCount, string groupName, int problemCount) {
+    private void CalculateHitsForEachBudget(Dictionary<string, SortedList<double, double>> hits, IndexedDataRow<double> row, bool maximization, int groupCount, string groupName, int problemCount, double bestTarget) {
       foreach (var b in budgets) {
         var key = groupName + "-" + b;
@@ -597,5 +608,6 @@
             // the budget may be too low to achieve any target
             if (prev == null && v.Item1 != b) break;
-            var tgt = (prev == null || v.Item1 == b) ? v.Item2 : prev.Item2;
+            var tgt = ((prev == null || v.Item1 == b) ? v.Item2 : prev.Item2);
+            tgt = maximization ? bestTarget / tgt : tgt / bestTarget;
             if (hits[key].ContainsKey(tgt))
               hits[key][tgt] += 1.0 / (groupCount * problemCount);
@@ -609,5 +621,5 @@
     }
 
-    private void CalculateHitsForAllBudgets(Dictionary<string, SortedList<double, double>> hits, IndexedDataRow<double> row, int groupCount, string groupName, int problemCount) {
+    private void CalculateHitsForAllBudgets(Dictionary<string, SortedList<double, double>> hits, IndexedDataRow<double> row, bool maximization, int groupCount, string groupName, int problemCount, double bestTarget) {
       var values = row.Values;
       if (!hits.ContainsKey(groupName)) hits.Add(groupName, new SortedList<double, double>());
@@ -621,4 +633,5 @@
           if (prev != null || current.Item1 == budgets[i]) {
             var tgt = (prev == null || current.Item1 == budgets[i]) ? current.Item2 : prev.Item2;
+            tgt = maximization ? bestTarget / tgt : tgt / bestTarget;
             if (!hits[groupName].ContainsKey(tgt)) hits[groupName][tgt] = 0;
             hits[groupName][tgt] += 1.0 / (groupCount * problemCount * budgets.Length);
@@ -631,4 +644,5 @@
       }
       var lastTgt = values.Last().Item2;
+      lastTgt = maximization ? bestTarget / lastTgt : lastTgt / bestTarget;
       if (i < budgets.Length && !hits[groupName].ContainsKey(lastTgt)) hits[groupName][lastTgt] = 0;
       while (i < budgets.Length) {
