1  #region License Information


2  /* HeuristicLab


3  * Copyright (C) 20022014 Heuristic and Evolutionary Algorithms Laboratory (HEAL)


4  *


5  * This file is part of HeuristicLab.


6  *


7  * HeuristicLab is free software: you can redistribute it and/or modify


8  * it under the terms of the GNU General Public License as published by


9  * the Free Software Foundation, either version 3 of the License, or


10  * (at your option) any later version.


11  *


12  * HeuristicLab is distributed in the hope that it will be useful,


13  * but WITHOUT ANY WARRANTY; without even the implied warranty of


14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the


15  * GNU General Public License for more details.


16  *


17  * You should have received a copy of the GNU General Public License


18  * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.


19  */


20  #endregion


21 


22  using System;


23  using System.Collections.Generic;


24  using System.Drawing;


25  using System.Linq;


26  using System.Windows.Forms;


27  using System.Windows.Forms.DataVisualization.Charting;


28 


29  namespace HeuristicLab.Visualization.ChartControlsExtensions {


30  public partial class HistogramControl : UserControl {


31  private static readonly string SeriesName = "Histogram";


32 


33  private List<double> points;


34  public int NumberOfBins {


35  get { return (int)binsNumericUpDown.Value; }


36  set { binsNumericUpDown.Value = value; }


37  }


38 


39  public int MinimumNumberOfBins {


40  get { return (int)binsNumericUpDown.Minimum; }


41  set { binsNumericUpDown.Minimum = value; }


42  }


43 


44  public int MaximumNumberOfBins {


45  get { return (int)binsNumericUpDown.Maximum; }


46  set { binsNumericUpDown.Maximum = value; }


47  }


48 


49  public int IncrementNumberOfBins {


50  get { return (int)binsNumericUpDown.Increment; }


51  set { binsNumericUpDown.Increment = value; }


52  }


53 


54  public bool CalculateExactBins {


55  get { return exactCheckBox.Checked; }


56  set { exactCheckBox.Checked = value; }


57  }


58 


59  public bool ShowExactCheckbox {


60  get { return exactCheckBox.Visible; }


61  set { exactCheckBox.Visible = value; }


62  }


63 


64  public HistogramControl() {


65  InitializeComponent();


66  points = new List<double>();


67  InitializeChart();


68  }


69 


70  public void AddPoint(double point) {


71  points.Add(point);


72  UpdateHistogram();


73  }


74 


75  public void AddPoints(IEnumerable<double> points) {


76  this.points.AddRange(points);


77  UpdateHistogram();


78  }


79 


80  public void ClearPoints() {


81  points.Clear();


82  UpdateHistogram();


83  }


84 


85  private void InitializeChart() {


86  chart.Series.Clear();


87  Series s = chart.Series.Add(SeriesName);


88  s.ChartType = SeriesChartType.Column;


89  s.BorderColor = Color.Black;


90  s.BorderWidth = 1;


91  s.BorderDashStyle = ChartDashStyle.Solid;


92  }


93 


94  private void UpdateHistogram() {


95  if (InvokeRequired) {


96  Invoke((Action)UpdateHistogram, null);


97  return;


98  }


99  Series histogramSeries = chart.Series[SeriesName];


100  histogramSeries.Points.Clear();


101 


102  if (!points.Any()) return;


103  int bins = (int)binsNumericUpDown.Value;


104 


105  double minValue = points.Min();


106  double maxValue = points.Max();


107  double intervalWidth = (maxValue  minValue) / bins;


108  if (intervalWidth <= 0) return;


109 


110  if (!exactCheckBox.Checked) {


111  intervalWidth = HumanRoundRange(intervalWidth);


112  minValue = Math.Floor(minValue / intervalWidth) * intervalWidth;


113  maxValue = Math.Ceiling(maxValue / intervalWidth) * intervalWidth;


114  }


115 


116  double current = minValue, intervalCenter = intervalWidth / 2.0;


117  int count = 0;


118  foreach (double v in points.OrderBy(x => x)) {


119  while (v > current + intervalWidth) {


120  histogramSeries.Points.AddXY(current + intervalCenter, count);


121  current += intervalWidth;


122  count = 0;


123  }


124  count++;


125  }


126  histogramSeries.Points.AddXY(current + intervalCenter, count);


127 


128  histogramSeries["PointWidth"] = "1";


129 


130  ChartArea chartArea = chart.ChartAreas[histogramSeries.ChartArea];


131  chartArea.AxisY.Title = "Frequency";


132  chartArea.AxisX.Minimum = minValue;


133  chartArea.AxisX.Maximum = maxValue;


134 


135  double axisInterval = intervalWidth;


136  while ((maxValue  minValue) / axisInterval > 10.0) {


137  axisInterval *= 2.0;


138  }


139  chartArea.AxisX.Interval = axisInterval;


140  }


141 


142  private double HumanRoundRange(double range) {


143  double base10 = Math.Pow(10.0, Math.Floor(Math.Log10(range)));


144  double rounding = range / base10;


145  if (rounding <= 1.5) rounding = 1;


146  else if (rounding <= 2.25) rounding = 2;


147  else if (rounding <= 3.75) rounding = 2.5;


148  else if (rounding <= 7.5) rounding = 5;


149  else rounding = 10;


150  return rounding * base10;


151  }


152 


153  private void binsNumericUpDown_ValueChanged(object sender, EventArgs e) {


154  UpdateHistogram();


155  }


156 


157  private void exactCheckBox_CheckedChanged(object sender, EventArgs e) {


158  UpdateHistogram();


159  }


160  }


161  }

