#region License Information /* HeuristicLab * Copyright (C) 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.Drawing; using System.Linq; using System.Windows.Forms; using System.Windows.Forms.DataVisualization.Charting; using HeuristicLab.Core.Views; using HeuristicLab.MainForm; namespace HeuristicLab.DatastreamAnalysis.Views { [View("DataBarSet")] [Content(typeof(DataBarSet), true)] public partial class DataBarSetView : ItemView { private bool updateInProgress; private string seriesName = "Ensembles"; public virtual Image ViewImage { get { return HeuristicLab.Common.Resources.VSImageLibrary.Graph; } } public new DataBarSet Content { get { return (DataBarSet) base.Content; } set { base.Content = value; } } public DataBarSetView() : base() { InitializeComponent(); updateInProgress = false; this.chart.CustomizeAllChartAreas(); this.chart.ChartAreas[0].CursorX.IsUserSelectionEnabled = true; this.chart.ChartAreas[0].AxisX.ScaleView.Zoomable = true; this.chart.ChartAreas[0].AxisX.Title = "Ensembles"; //this.chart.ChartAreas[0].AxisX.Maximum = 0.0; //this.chart.ChartAreas[0].AxisX.Maximum = (Content != null && Content.Bars != null) ? Content.Bars.Count : 0.0; //AddCustomLabelsToAxis(this.chart.ChartAreas[0].AxisX); this.chart.ChartAreas[0].AxisY.Title = "Estimation Quality"; this.chart.ChartAreas[0].AxisY.IsStartedFromZero = true; this.chart.ChartAreas[0].AxisY.Minimum = 0.0; this.chart.ChartAreas[0].AxisY.Maximum = 1.0; this.chart.ChartAreas[0].AxisY.Interval = 0.1; this.chart.ChartAreas[0].CursorY.IsUserSelectionEnabled = true; this.chart.ChartAreas[0].AxisX.ScaleView.Zoomable = true; } private void AddCustomLabelsToAxis(Axis axis) { axis.CustomLabels.Clear(); var bars = Content.Bars.ToList(); for(int i = 0; i < Content.Bars.Count; i++) { CustomLabel barLabel = new CustomLabel(); barLabel.Text = bars[i].Name; barLabel.FromPosition = i; barLabel.ToPosition = i + 1; axis.CustomLabels.Add(barLabel); } } protected override void RegisterContentEvents() { base.RegisterContentEvents(); Content.BarsPropertyChanged += new EventHandler(Content_BarsChanged); Content.BarValueChanged += new EventHandler(Content_BarValuesChanged); Content.ThresholdsPropertyChanged += new EventHandler(Content_ThresholdsChanged); } protected override void DeregisterContentEvents() { base.DeregisterContentEvents(); Content.BarsPropertyChanged -= new EventHandler(Content_BarsChanged); Content.BarValueChanged -= new EventHandler(Content_BarValuesChanged); Content.ThresholdsPropertyChanged -= new EventHandler(Content_ThresholdsChanged); } private void Content_BarsChanged(object sender, EventArgs e) { UpdateChart(); } private void Content_BarValuesChanged(object sender, EventArgs e) { UpdateChartValues(); } private void Content_ThresholdsChanged(object sender, EventArgs e) { UpdateChart(); } protected override void OnContentChanged() { base.OnContentChanged(); UpdateChart(); } private void UpdateChart() { if (InvokeRequired) { Invoke((Action) UpdateChart); } else if(!updateInProgress) { if (Content == null) return; updateInProgress = true; chart.Series.Clear(); Series series = chart.Series.Add(seriesName); series.IsVisibleInLegend = false; series.ChartType = SeriesChartType.Column; int i = 0; foreach (var bar in Content.Bars) { var dp = new DataPoint(i, bar.Value) { AxisLabel = bar.Name, ToolTip = bar.Name, Color = bar.BarColor, BorderWidth = 5 }; series.Points.Add(dp); i++; } //chart.ChartAreas[0].RecalculateAxesScale(); AddThresholds(); CheckThresholds(); chart.Refresh(); updateInProgress = false; } } private void UpdateChartValues() { if (InvokeRequired) { Invoke((Action) UpdateChartValues); } else if(!updateInProgress) { if (Content == null) return; updateInProgress = true; //chart.Series[seriesName].Points.Clear(); //foreach (var bar in Content.Bars) { // chart.Series[seriesName].Points.AddXY(bar.Name, bar.Value); //} var bars = Content.Bars.ToList(); for (int i = 0; i < bars.Count; i++) { chart.Series[seriesName].Points.ElementAt(i).SetValueY(bars[i].Value); chart.Series[seriesName].Points.ElementAt(i).ToolTip = bars[i].Name + " = " + bars[i].Value; } CheckThresholds(); //chart.ChartAreas[0].RecalculateAxesScale(); chart.Refresh(); updateInProgress = false; } } public static Color DefaultColor = Color.FromArgb(65, 140, 240); public static Color HighlightColor1 = Color.FromArgb(37, 105, 175); public static Color HighlightColor2 = Color.FromArgb(247, 150, 70); public static Color HighlightColor3 = Color.FromArgb(228, 108, 10); //public static Color HighlightColor1 = Color.FromArgb(45, 120, 200); //public static Color HighlightColor2 = Color.FromArgb(15, 90, 160); //public static Color HighlightColor3 = Color.FromArgb(10, 60, 110); private void CheckThresholds() { var bars = Content.Bars.ToList(); var winner = !bars.Any() ? -1 : bars .Select((value, index) => new {Value = value, Index = index}) .Aggregate((a, b) => ((a.Value.Value - a.Value.ThresholdUpperBound) > (b.Value.Value - b.Value.ThresholdUpperBound)) ? a : b) .Index; // color bars depending on the threshold boundaries they exceed for (int i = 0; i < bars.Count; i++) { var bar = bars[i]; if (bar.Value > bar.ThresholdUpperBound) { chart.Series[seriesName].Points[i].Color = HighlightColor2; chart.Series[seriesName].Points[i].BorderColor = HighlightColor2; } else if (bar.Value > bar.ThresholdLowerBound) { chart.Series[seriesName].Points[i].Color = HighlightColor1; chart.Series[seriesName].Points[i].BorderColor = HighlightColor1; } else { chart.Series[seriesName].Points[i].Color = bar.BarColor; chart.Series[seriesName].Points[i].BorderColor = bar.BarColor; } } // color the winner's border if (winner != -1 && bars[winner].Value > bars[winner].ThresholdUpperBound) { chart.Series[seriesName].Points[winner].BorderColor = HighlightColor3; } } private void AddThresholds() { Series series = chart.Series.Add("Thresholds"); series.IsVisibleInLegend = false; series.ChartType = SeriesChartType.ErrorBar; int i = 0; foreach (var bar in Content.Bars) { string desc = string.Format("{0} - Threshold [{1},{2}]", bar.Name, bar.ThresholdLowerBound,bar.ThresholdUpperBound); var threshold = new DataPoint(i, new[] {(bar.ThresholdLowerBound + bar.ThresholdUpperBound)/2, bar.ThresholdLowerBound, bar.ThresholdUpperBound}) { AxisLabel = desc, ToolTip = desc, Color = bar.ThresholdColor, BorderWidth = 1 }; series.Points.Add(threshold); i++; } } private void AddThresholdsOld() { Series series = chart.Series.Add("Thresholds"); series.IsVisibleInLegend = false; series.ChartType = SeriesChartType.StackedColumn; int i = 0; foreach (var bar in Content.Bars) { //series.Points.Add(new DataPoint(i, new [] { bar.Threshold, bar.Threshold + 0.05 }) { AxisLabel = bar.Name, Color = Color.Transparent, BorderWidth = 2, BorderColor = bar.ThresholdColor}); series.Points.Add(new DataPoint(i, new[] { bar.ThresholdLowerBound, bar.ThresholdUpperBound }) { AxisLabel = bar.Name, Color = bar.ThresholdColor }); i++; } } private void AddThresholdsOld2() { chart.Annotations.Clear(); var bars = Content.Bars.ToList(); for (int i = 0; i < bars.Count; i++) { HorizontalLineAnnotation annotation = new HorizontalLineAnnotation(); annotation.AllowMoving = false; annotation.AllowResizing = false; annotation.LineWidth = 2; annotation.LineColor = bars[i].ThresholdColor; annotation.IsInfinitive = false; annotation.ClipToChartArea = chart.ChartAreas[0].Name; annotation.AxisX = chart.ChartAreas[0].AxisX; annotation.AxisY = chart.ChartAreas[0].AxisY; annotation.Y = bars[i].ThresholdLowerBound; annotation.Alignment = ContentAlignment.MiddleCenter; annotation.AnchorX = i; annotation.X = i - 0.4; annotation.Width = (46 - bars.Count) / bars.Count; annotation.Name = bars[i].Name; annotation.Tag = bars[i].Name; annotation.BringToFront(); chart.Annotations.Add(annotation); } } private TextAnnotation CreateTextAnnotation(string name, int classIndex, Axis axisX, Axis axisY, double x, double y, ContentAlignment alignment) { TextAnnotation annotation = new TextAnnotation(); annotation.Text = name; annotation.AllowMoving = true; annotation.AllowResizing = false; annotation.AllowSelecting = false; annotation.IsSizeAlwaysRelative = true; annotation.ClipToChartArea = chart.ChartAreas[0].Name; annotation.Tag = classIndex; annotation.AxisX = axisX; annotation.AxisY = axisY; annotation.Alignment = alignment; annotation.X = x; annotation.Y = y; return annotation; } #region user interaction events private void chart_MouseMove(object sender, MouseEventArgs e) { HitTestResult result = chart.HitTest(e.X, e.Y); if (result.ChartElementType == ChartElementType.LegendItem) this.Cursor = Cursors.Hand; else this.Cursor = Cursors.Default; } private void chart_MouseDown(object sender, MouseEventArgs e) { HitTestResult result = chart.HitTest(e.X, e.Y); if (result.ChartElementType == ChartElementType.LegendItem) { if (result.Series != null) ToggleSeries(result.Series); } } private void ToggleSeries(Series series) { if (series.Points.Count == 0) { // TODO } else { series.Points.Clear(); } } private void chart_AnnotationPositionChanging(object sender, AnnotationPositionChangingEventArgs e) { int classIndex = (int)e.Annotation.Tag; //double[] thresholds = Content.Model.Thresholds.ToArray(); //thresholds[classIndex] = e.NewLocationY; //Array.Sort(thresholds); //Content.Model.SetThresholdsAndClassValues(thresholds, Content.Model.ClassValues); } private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) { foreach (LegendItem legendItem in e.LegendItems) { var series = chart.Series[legendItem.SeriesName]; if (series != null) { bool seriesIsInvisible = series.Points.Count == 0; foreach (LegendCell cell in legendItem.Cells) cell.ForeColor = seriesIsInvisible ? Color.Gray : Color.Black; } } } #endregion } }