Changeset 14101 for branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.cs
- Timestamp:
- 07/18/16 16:54:16 (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.cs
r14035 r14101 20 20 #endregion 21 21 22 using HeuristicLab.Analysis;23 using HeuristicLab.Collections;24 using HeuristicLab.Core.Views;25 using HeuristicLab.Data;26 using HeuristicLab.MainForm;27 using HeuristicLab.MainForm.WindowsForms;28 22 using System; 29 23 using System.Collections.Generic; … … 33 27 using System.Linq; 34 28 using System.Windows.Forms; 29 using System.Windows.Forms.DataVisualization.Charting; 30 using HeuristicLab.Analysis; 31 using HeuristicLab.Collections; 32 using HeuristicLab.Core.Views; 33 using HeuristicLab.Data; 34 using HeuristicLab.MainForm; 35 using HeuristicLab.MainForm.WindowsForms; 35 36 36 37 namespace HeuristicLab.Optimization.Views { … … 38 39 [Content(typeof(RunCollection), false)] 39 40 public partial class RunCollectionRLDView : ItemView { 41 private List<Series> invisibleTargetSeries; 42 40 43 private const string AllRuns = "All Runs"; 41 44 … … 56 59 Color.FromArgb(0x63, 0xC2, 0x16), 57 60 }; 58 private static readonly DataRowVisualProperties.DataRowLineStyle[] lineStyles = new[] { 61 private static readonly ChartDashStyle[] lineStyles = new[] { 62 ChartDashStyle.Solid, 63 ChartDashStyle.Dash, 64 ChartDashStyle.DashDot, 65 ChartDashStyle.Dot 66 }; 67 private static readonly DataRowVisualProperties.DataRowLineStyle[] hlLineStyles = new[] { 59 68 DataRowVisualProperties.DataRowLineStyle.Solid, 60 69 DataRowVisualProperties.DataRowLineStyle.Dash, … … 72 81 73 82 private bool suppressUpdates; 74 private readonly IndexedDataTable<double> byTargetDataTable;75 public IndexedDataTable<double> ByTargetDataTable {76 get { return byTargetDataTable; }77 }78 83 private readonly IndexedDataTable<double> byCostDataTable; 79 84 public IndexedDataTable<double> ByCostDataTable { … … 83 88 public RunCollectionRLDView() { 84 89 InitializeComponent(); 85 byTargetDataTable = new IndexedDataTable<double>("ECDF by Target", "A data table containing the ECDF of each of a number of groups.") { 86 VisualProperties = { 87 YAxisTitle = "Proportion of reached targets", 88 YAxisMinimumFixedValue = 0, 89 YAxisMinimumAuto = false, 90 YAxisMaximumFixedValue = 1, 91 YAxisMaximumAuto = false 92 } 93 }; 94 byTargetViewHost.Content = byTargetDataTable; 90 invisibleTargetSeries = new List<Series>(); 91 92 targetChart.CustomizeAllChartAreas(); 93 targetChart.ChartAreas[0].CursorX.Interval = 1; 94 targetChart.SuppressExceptions = true; 95 95 byCostDataTable = new IndexedDataTable<double>("ECDF by Cost", "A data table containing the ECDF of each of a number of groups.") { 96 96 VisualProperties = { … … 196 196 dataTableComboBox.Items.Clear(); 197 197 groupComboBox.Items.Clear(); 198 byTargetDataTable.Rows.Clear(); 198 targetChart.ChartAreas[0].AxisX.IsLogarithmic = false; 199 targetChart.Series.Clear(); 200 invisibleTargetSeries.Clear(); 201 byCostDataTable.VisualProperties.XAxisLogScale = false; 202 byCostDataTable.Rows.Clear(); 199 203 200 204 UpdateCaption(); … … 309 313 private void UpdateResultsByTarget() { 310 314 // necessary to reset log scale -> empty chart cannot use log scaling 311 byTargetDataTable.VisualProperties.XAxisLogScale = false; 312 byTargetDataTable.Rows.Clear(); 315 targetChart.ChartAreas[0].AxisX.IsLogarithmic = false; 316 targetChart.Series.Clear(); 317 invisibleTargetSeries.Clear(); 313 318 314 319 var table = (string)dataTableComboBox.SelectedItem; … … 324 329 var lineStyleCount = 0; 325 330 331 // if the group contains multiple different problem instances we want to use the 332 // minimal maximal observed effort otherwise we run into situations where we don't 333 // have data for a certain problem instance anymore this is a special case when 334 // aggregating over multiple problem instances 326 335 var maxEfforts = new Dictionary<ProblemDescription, double>(); 336 double minEff = double.MaxValue, maxEff = double.MinValue; 327 337 foreach (var group in groupedRuns) { 328 338 foreach (var problem in group.Value) { 329 double eff; 330 if (!maxEfforts.TryGetValue(problem.Key, out eff)) { 331 eff = 0.0; 332 } 339 double problemSpecificMaxEff; 340 if (!maxEfforts.TryGetValue(problem.Key, out problemSpecificMaxEff)) { 341 problemSpecificMaxEff = 0; 342 } 343 var bestKnownTarget = problem.Value.Item1; 344 var max = problem.Key.IsMaximization(); 345 var worstTarget = (max ? (1 - targets.Max()) : (1 + targets.Max())) * bestKnownTarget; 346 var bestTarget = (max ? (1 - targets.Min()) : (1 + targets.Min())) * bestKnownTarget; 333 347 foreach (var run in problem.Value.Item2) { 334 var maxEff = ((IndexedDataTable<double>)run.Results[table]).Rows.First().Values.Last().Item1; 335 if (maxEff > eff) eff = maxEff; 336 } 337 maxEfforts[problem.Key] = eff; 338 } 339 } 340 // if the group contains multiple different problems we want to use the minimal maximal observed effort 341 // otherwise we run into situations where we don't have data for a certain problem instance anymore 342 // this is a special case when aggregating over multiple problem instances 343 var maxEffort = maxEfforts.Values.Min(); 348 var row = ((IndexedDataTable<double>)run.Results[table]).Rows.First().Values; 349 var a = row.FirstOrDefault(x => max ? x.Item2 >= worstTarget : x.Item2 <= worstTarget); 350 var b = row.FirstOrDefault(x => max ? x.Item2 >= bestTarget : x.Item2 <= bestTarget); 351 var firstEff = (a == default(Tuple<double, double>)) ? row.Last().Item1 : a.Item1; 352 var lastEff = (b == default(Tuple<double, double>)) ? row.Last().Item1 : b.Item1; 353 if (minEff > firstEff) minEff = firstEff; 354 if (maxEff < lastEff) maxEff = lastEff; 355 if (problemSpecificMaxEff < lastEff) problemSpecificMaxEff = lastEff; 356 } 357 maxEfforts[problem.Key] = problemSpecificMaxEff; 358 } 359 } 360 maxEff = Math.Min(maxEff, maxEfforts.Values.Min()); 361 362 var minZeros = (int)Math.Floor(Math.Log10(minEff)); 363 var maxZeros = (int)Math.Floor(Math.Log10(maxEff)); 364 var axisMin = (decimal)Math.Pow(10, minZeros); 365 var axisMax = (decimal)Math.Pow(10, maxZeros); 366 if (!targetLogScalingCheckBox.Checked) { 367 var minAdd = (decimal)Math.Pow(10, minZeros - 1) * 2; 368 var maxAdd = (decimal)Math.Pow(10, maxZeros - 1) * 2; 369 while (axisMin + minAdd < (decimal)minEff) axisMin += minAdd; 370 while (axisMax <= (decimal)maxEff) axisMax += maxAdd; 371 } else axisMax = (decimal)Math.Pow(10, (int)Math.Ceiling(Math.Log10(maxEff))); 372 targetChart.ChartAreas[0].AxisX.Minimum = (double)axisMin; 373 targetChart.ChartAreas[0].AxisX.Maximum = (double)axisMax; 344 374 345 375 foreach (var group in groupedRuns) { … … 358 388 xAxisTitles.Add(resultsTable.VisualProperties.XAxisTitle); 359 389 360 if (eachOrAllTargetCheckBox.Checked) { 361 CalculateHitsForEachTarget(hits, misses, resultsTable.Rows.First(), problem.Key, group.Key, problem.Value.Item1, maxEffort); 362 // achiving each target can be seen as a separate run for that target only 363 noRuns += targets.Length; 390 if (aggregateTargetsCheckBox.Checked) { 391 var length = CalculateHitsForAllTargets(hits, misses, resultsTable.Rows.First(), problem.Key, group.Key, problem.Value.Item1, maxEff); 392 maxLength = Math.Max(length, maxLength); 364 393 } else { 365 var length = CalculateHitsForAllTargets(hits, misses, resultsTable.Rows.First(), problem.Key, group.Key, problem.Value.Item1, maxEffort); 366 maxLength = Math.Max(length, maxLength); 367 noRuns++; 394 CalculateHitsForEachTarget(hits, misses, resultsTable.Rows.First(), problem.Key, group.Key, problem.Value.Item1, maxEff); 368 395 } 369 }370 }371 396 noRuns++; 397 } 398 } 372 399 foreach (var list in hits) { 373 var row = new IndexedDataRow<double>(list.Key) { 374 VisualProperties = { 375 ChartType = DataRowVisualProperties.DataRowChartType.StepLine, 376 LineWidth = 2, 377 Color = colors[colorCount], 378 LineStyle = lineStyles[lineStyleCount], 379 StartIndexZero = false 400 var row = new Series(list.Key) { 401 ChartType = SeriesChartType.StepLine, 402 BorderWidth = 2, 403 Color = colors[colorCount], 404 BorderDashStyle = lineStyles[lineStyleCount], 405 }; 406 var rowShade = new Series(list.Key + "-range") { 407 IsVisibleInLegend = false, 408 ChartType = SeriesChartType.Range, 409 Color = Color.FromArgb(32, colors[colorCount]) 410 }; 411 412 var ecdf = 0.0; 413 var missedecdf = 0.0; 414 var iter = misses[list.Key].GetEnumerator(); 415 var moreMisses = iter.MoveNext(); 416 var totalTargets = noRuns; 417 if (aggregateTargetsCheckBox.Checked) totalTargets *= targets.Length; 418 var movingTargets = totalTargets; 419 foreach (var h in list.Value) { 420 while (moreMisses && iter.Current.Key <= h.Key) { 421 missedecdf += iter.Current.Value; 422 movingTargets -= iter.Current.Value; 423 if (row.Points.Count > 0 && row.Points.Last().XValue == iter.Current.Key) 424 row.Points.Last().SetValueY(ecdf / movingTargets); 425 else row.Points.AddXY(iter.Current.Key, ecdf / movingTargets); 426 if (boundShadingCheckBox.Checked) { 427 if (rowShade.Points.Count > 0 && rowShade.Points.Last().XValue == iter.Current.Key) 428 rowShade.Points.Last().SetValueY(ecdf / totalTargets, (ecdf + missedecdf) / totalTargets); 429 else rowShade.Points.Add(new DataPoint(iter.Current.Key, new[] { ecdf / totalTargets, (ecdf + missedecdf) / totalTargets })); 430 } 431 moreMisses = iter.MoveNext(); 380 432 } 381 };382 383 var ecdf = 0.0;384 var iter = misses[list.Key].GetEnumerator();385 iter.MoveNext();386 var sumTargets = noRuns * targets.Length;387 foreach (var h in list.Value) {388 433 ecdf += h.Value; 389 while (iter.Current.Key < h.Key) { 390 sumTargets -= iter.Current.Value; 391 if (!iter.MoveNext()) break; 434 if (row.Points.Count > 0 && row.Points.Last().XValue == h.Key) 435 row.Points.Last().SetValueY(ecdf / movingTargets); 436 else row.Points.AddXY(h.Key, ecdf / movingTargets); 437 if (missedecdf > 0 && boundShadingCheckBox.Checked) { 438 if (rowShade.Points.Count > 0 && rowShade.Points.Last().XValue == h.Key) 439 rowShade.Points.Last().SetValueY(ecdf / totalTargets, (ecdf + missedecdf) / totalTargets); 440 else rowShade.Points.Add(new DataPoint(h.Key, new[] { ecdf / totalTargets, (ecdf + missedecdf) / totalTargets })); 392 441 } 393 row.Values.Add(Tuple.Create(h.Key, ecdf / sumTargets)); 394 } 395 396 if (maxLength > 0 && (row.Values.Count == 0 || row.Values.Last().Item1 < maxLength)) 397 row.Values.Add(Tuple.Create(maxLength, ecdf / sumTargets)); 398 399 byTargetDataTable.Rows.Add(row); 442 } 443 444 while (moreMisses) { 445 // if there are misses beyond the last hit we extend the shaded area 446 missedecdf += iter.Current.Value; 447 //movingTargets -= iter.Current.Value; 448 if (row.Points.Count > 0 && row.Points.Last().XValue == iter.Current.Key) 449 row.Points.Last().SetValueY(ecdf / movingTargets); 450 else row.Points.AddXY(iter.Current.Key, ecdf / movingTargets); 451 if (boundShadingCheckBox.Checked) { 452 if (rowShade.Points.Count > 0 && rowShade.Points.Last().XValue == iter.Current.Key) 453 rowShade.Points.Last().SetValueY(ecdf / totalTargets, (ecdf + missedecdf) / totalTargets); 454 else rowShade.Points.Add(new DataPoint(iter.Current.Key, new[] { ecdf / totalTargets, (ecdf + missedecdf) / totalTargets })); 455 } 456 moreMisses = iter.MoveNext(); 457 } 458 459 if (maxLength > 0 && (row.Points.Count == 0 || row.Points.Last().XValue < maxLength)) 460 row.Points.AddXY(maxLength, ecdf / movingTargets); 461 462 if (row.Points.Count > 0) { 463 var point = row.Points.Last(); 464 point.Label = row.Name; 465 point.MarkerStyle = MarkerStyle.Cross; 466 point.MarkerBorderWidth = 1; 467 } 468 469 ConfigureSeries(row); 470 targetChart.Series.Add(rowShade); 471 targetChart.Series.Add(row); 400 472 } 401 473 colorCount = (colorCount + 1) % colors.Length; … … 404 476 405 477 if (targets.Length == 1) 406 ByTargetDataTable.VisualProperties.YAxisTitle = "Probability to be " + (targets[0] * 100) + "% worse than best";407 else ByTargetDataTable.VisualProperties.YAxisTitle = "Proportion of reached targets";408 byTargetDataTable.VisualProperties.XAxisTitle = string.Join(" / ", xAxisTitles);409 byTargetDataTable.VisualProperties.XAxisLogScale = byTargetDataTable.Rows.Count > 0 && targetLogScalingCheckBox.Checked;410 478 targetChart.ChartAreas[0].AxisY.Title = "Probability to be " + (targets[0] * 100) + "% worse than best"; 479 else targetChart.ChartAreas[0].AxisY.Title = "Proportion of reached targets"; 480 targetChart.ChartAreas[0].AxisX.Title = string.Join(" / ", xAxisTitles); 481 targetChart.ChartAreas[0].AxisX.IsLogarithmic = CanDisplayLogarithmic(); 482 targetChart.ChartAreas[0].CursorY.Interval = 0.05; 411 483 UpdateErtTables(groupedRuns); 412 484 } … … 423 495 IndexedDataRow<double> row, ProblemDescription problem, 424 496 string group, double bestTarget, double maxEffort) { 425 foreach (var l in targets.Select(x => (problem.IsMaximization() ? (1 - x) : (1 + x)) * bestTarget)) { 426 var key = group + "-" + l; 497 foreach (var t in targets.Select(x => Tuple.Create((problem.IsMaximization() ? (1 - x) : (1 + x)) * bestTarget, x))) { 498 var l = t.Item1; 499 var key = group + "_" + (t.Item2 * 100) + "%_" + l; 427 500 if (!hits.ContainsKey(key)) { 428 501 hits.Add(key, new SortedList<double, int>()); … … 572 645 LineWidth = 2, 573 646 Color = colors[colorCount], 574 LineStyle = lineStyles[lineStyleCount],647 LineStyle = hlLineStyles[lineStyleCount], 575 648 StartIndexZero = false 576 649 } … … 688 761 689 762 private void logScalingCheckBox_CheckedChanged(object sender, EventArgs e) { 690 byTargetDataTable.VisualProperties.XAxisLogScale = byTargetDataTable.Rows.Count > 0 && targetLogScalingCheckBox.Checked;763 UpdateResultsByTarget(); 691 764 byCostDataTable.VisualProperties.XAxisLogScale = byCostDataTable.Rows.Count > 0 && budgetLogScalingCheckBox.Checked; 765 } 766 767 private void boundShadingCheckBox_CheckedChanged(object sender, EventArgs e) { 768 UpdateResultsByTarget(); 692 769 } 693 770 … … 722 799 } 723 800 724 private void eachOrAllTargetCheckBox_CheckedChanged(object sender, EventArgs e) { 725 var each = eachOrAllTargetCheckBox.Checked; 726 eachOrAllTargetCheckBox.Text = each ? "each" : "all"; 801 private void aggregateTargetsCheckBox_CheckedChanged(object sender, EventArgs e) { 727 802 SuspendRepaint(); 728 803 try { … … 918 993 #endregion 919 994 995 private void ConfigureSeries(Series series) { 996 series.SmartLabelStyle.Enabled = true; 997 series.SmartLabelStyle.AllowOutsidePlotArea = LabelOutsidePlotAreaStyle.No; 998 series.SmartLabelStyle.CalloutLineAnchorCapStyle = LineAnchorCapStyle.None; 999 series.SmartLabelStyle.CalloutLineColor = series.Color; 1000 series.SmartLabelStyle.CalloutLineWidth = 2; 1001 series.SmartLabelStyle.CalloutStyle = LabelCalloutStyle.Underlined; 1002 series.SmartLabelStyle.IsOverlappedHidden = false; 1003 series.SmartLabelStyle.MaxMovingDistance = 200; 1004 series.ToolTip = series.LegendText + " X = #VALX, Y = #VALY"; 1005 } 1006 1007 private void chart_MouseDown(object sender, MouseEventArgs e) { 1008 HitTestResult result = targetChart.HitTest(e.X, e.Y); 1009 if (result.ChartElementType == ChartElementType.LegendItem) { 1010 ToggleTargetChartSeriesVisible(result.Series); 1011 } 1012 } 1013 private void chart_MouseMove(object sender, MouseEventArgs e) { 1014 HitTestResult result = targetChart.HitTest(e.X, e.Y); 1015 if (result.ChartElementType == ChartElementType.LegendItem) 1016 this.Cursor = Cursors.Hand; 1017 else 1018 this.Cursor = Cursors.Default; 1019 } 1020 private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) { 1021 foreach (LegendItem legendItem in e.LegendItems) { 1022 var series = targetChart.Series[legendItem.SeriesName]; 1023 if (series != null) { 1024 bool seriesIsInvisible = invisibleTargetSeries.Any(x => x.Name == series.Name); 1025 foreach (LegendCell cell in legendItem.Cells) { 1026 cell.ForeColor = seriesIsInvisible ? Color.Gray : Color.Black; 1027 } 1028 } 1029 } 1030 } 1031 1032 private void ToggleTargetChartSeriesVisible(Series series) { 1033 var indexList = invisibleTargetSeries.FindIndex(x => x.Name == series.Name); 1034 var indexChart = targetChart.Series.IndexOf(series); 1035 if (targetChart.Series.Count == 1) targetChart.ChartAreas[0].AxisX.IsLogarithmic = false; 1036 targetChart.Series.RemoveAt(indexChart); 1037 var s = indexList >= 0 ? invisibleTargetSeries[indexList] : new Series(series.Name) { 1038 Color = series.Color, 1039 ChartType = series.ChartType, 1040 BorderWidth = series.BorderWidth, 1041 BorderDashStyle = series.BorderDashStyle 1042 }; 1043 if (indexList < 0) { 1044 // hide 1045 invisibleTargetSeries.Add(series); 1046 var shadeSeries = targetChart.Series.FirstOrDefault(x => x.Name == series.Name + "-range"); 1047 if (shadeSeries != null) { 1048 if (targetChart.Series.Count == 1) targetChart.ChartAreas[0].AxisX.IsLogarithmic = false; 1049 targetChart.Series.Remove(shadeSeries); 1050 invisibleTargetSeries.Add(shadeSeries); 1051 indexChart--; 1052 } 1053 } else { 1054 // show 1055 invisibleTargetSeries.RemoveAt(indexList); 1056 var shadeSeries = invisibleTargetSeries.FirstOrDefault(x => x.Name == series.Name + "-range"); 1057 if (shadeSeries != null) { 1058 invisibleTargetSeries.Remove(shadeSeries); 1059 InsertOrAddSeries(indexChart, shadeSeries); 1060 indexChart++; 1061 } 1062 } 1063 InsertOrAddSeries(indexChart, s); 1064 targetChart.ChartAreas[0].AxisX.IsLogarithmic = CanDisplayLogarithmic(); 1065 } 1066 1067 private bool CanDisplayLogarithmic() { 1068 return targetLogScalingCheckBox.Checked 1069 && targetChart.Series.Count > 0 // must have a series 1070 && targetChart.Series.Any(x => x.Points.Count > 0) // at least one series must have points 1071 && targetChart.Series.All(s => s.Points.All(p => p.XValue > 0)); // all points must be positive 1072 } 1073 1074 private void InsertOrAddSeries(int index, Series s) { 1075 if (targetChart.Series.Count <= index) 1076 targetChart.Series.Add(s); 1077 else targetChart.Series.Insert(index, s); 1078 } 920 1079 921 1080 private class ProblemDescription {
Note: See TracChangeset
for help on using the changeset viewer.