#region License Information
/* HeuristicLab
* Copyright (C) 2002-2019 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 .
*/
#endregion
using System;
using System.Linq;
using HeuristicLab.Analysis;
using HeuristicLab.Common;
using HeuristicLab.Core.Views;
using HeuristicLab.MainForm;
using HeuristicLab.Problems.TestFunctions.MultiObjective;
namespace HeuristicLab.Problems.TestFunctions.Views {
[View("Scatter Plot")]
[Content(typeof(ParetoFrontScatterPlot))]
public partial class ParetoFrontScatterPlotView : ItemView {
private readonly ScatterPlot scatterPlot;
private readonly ScatterPlotDataRow qualitiesRow;
private readonly ScatterPlotDataRow paretoFrontRow;
private int oldObjectives = -1;
private int oldProblemSize = -1;
private bool suppressEvents;
public new ParetoFrontScatterPlot Content {
get { return (ParetoFrontScatterPlot)base.Content; }
set { base.Content = value; }
}
public ParetoFrontScatterPlotView() {
InitializeComponent();
scatterPlot = new ScatterPlot();
qualitiesRow = new ScatterPlotDataRow("Qualities", string.Empty, Enumerable.Empty>()) {
VisualProperties = {
PointSize = 8 ,
PointStyle = ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Circle
}
};
scatterPlot.Rows.Add(qualitiesRow);
paretoFrontRow = new ScatterPlotDataRow("Best Known Pareto Front", string.Empty, Enumerable.Empty>()) {
VisualProperties = {
PointSize = 4,
PointStyle = ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Square
}
};
scatterPlot.Rows.Add(paretoFrontRow);
}
protected override void OnContentChanged() {
base.OnContentChanged();
if (Content == null) {
scatterPlotView.Content = null;
xAxisComboBox.Items.Clear();
xAxisComboBox.SelectedIndex = -1;
yAxisComboBox.Items.Clear();
yAxisComboBox.SelectedIndex = -1;
return;
}
scatterPlotView.Content = scatterPlot;
if (oldObjectives != Content.Objectives || oldProblemSize != Content.ProblemSize)
UpdateAxisComboBoxes();
UpdateChartData();
oldObjectives = Content.Objectives;
oldProblemSize = Content.ProblemSize;
}
private void UpdateChartData() {
if (InvokeRequired) {
Invoke((Action)UpdateChartData);
return;
}
int xDimGlobal = xAxisComboBox.SelectedIndex;
int yDimGlobal = yAxisComboBox.SelectedIndex;
qualitiesRow.Points.Replace(CreatePoints(Content.Qualities, Content.Solutions, xDimGlobal, yDimGlobal));
paretoFrontRow.Points.Replace(CreatePoints(Content.ParetoFront, null, xDimGlobal, yDimGlobal));
paretoFrontRow.VisualProperties.IsVisibleInLegend = paretoFrontRow.Points.Count > 0; // hide if empty
}
private void UpdateAxisComboBoxes() {
try {
suppressEvents = true;
string prevSelectedX = (string)xAxisComboBox.SelectedItem;
string prevSelectedY = (string)yAxisComboBox.SelectedItem;
xAxisComboBox.Items.Clear();
yAxisComboBox.Items.Clear();
// Add Objectives first
for (int i = 0; i < Content.Objectives; i++) {
xAxisComboBox.Items.Add("Objective " + i);
yAxisComboBox.Items.Add("Objective " + i);
}
// Add Problem Dimension
for (int i = 0; i < Content.ProblemSize; i++) {
xAxisComboBox.Items.Add("Problem Dimension " + i);
yAxisComboBox.Items.Add("Problem Dimension " + i);
}
// Selection
int count = xAxisComboBox.Items.Count;
if (count > 0) {
if (prevSelectedX != null && xAxisComboBox.Items.Contains(prevSelectedX))
xAxisComboBox.SelectedItem = prevSelectedX;
else xAxisComboBox.SelectedIndex = 0;
if (prevSelectedY != null && yAxisComboBox.Items.Contains(prevSelectedY))
yAxisComboBox.SelectedItem = prevSelectedY;
else yAxisComboBox.SelectedIndex = Math.Min(1, count - 1);
} else {
xAxisComboBox.SelectedIndex = -1;
yAxisComboBox.SelectedIndex = -1;
}
UpdateAxisDescription();
} finally {
suppressEvents = false;
}
}
private void UpdateAxisDescription() {
scatterPlot.VisualProperties.XAxisTitle = (string)xAxisComboBox.SelectedItem;
scatterPlot.VisualProperties.YAxisTitle = (string)yAxisComboBox.SelectedItem;
}
private static Point2D[] CreatePoints(double[][] qualities, double[][] solutions, int xDimGlobal, int yDimGlobal) {
if (qualities == null || qualities.Length == 0) return new Point2D[0];
int objectives = qualities[0].Length;
// "Global" dimension index describes the index as if the qualities and solutions would be in a single array
// If the global dimension index is too long for the qualities, use solutions
var xDimArray = xDimGlobal < objectives ? qualities : solutions;
var yDimArray = yDimGlobal < objectives ? qualities : solutions;
var xDimIndex = xDimGlobal < objectives ? xDimGlobal : xDimGlobal - objectives;
var yDimIndex = yDimGlobal < objectives ? yDimGlobal : yDimGlobal - objectives;
if (xDimArray == null || yDimArray == null)
return new Point2D[0];
var points = new Point2D[xDimArray.Length];
for (int i = 0; i < xDimArray.Length; i++) {
points[i] = new Point2D(xDimArray[i][xDimIndex], yDimArray[i][yDimIndex]);
}
return points;
}
#region Event Handler
private void axisComboBox_SelectedIndexChanged(object sender, EventArgs e) {
if (suppressEvents) return;
UpdateAxisDescription();
UpdateChartData();
}
#endregion
}
}