- Timestamp:
- 01/23/17 16:11:02 (7 years ago)
- Location:
- branches/PerformanceComparison/HeuristicLab.Analysis.Views
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/PerformanceComparison/HeuristicLab.Analysis.Views
-
branches/PerformanceComparison/HeuristicLab.Analysis.Views/3.3/DataTableView.cs
r12012 r14600 1 1 #region License Information 2 2 /* HeuristicLab 3 * Copyright (C) 2002-201 5Heuristic and Evolutionary Algorithms Laboratory (HEAL)3 * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL) 4 4 * 5 5 * This file is part of HeuristicLab. … … 20 20 #endregion 21 21 22 using HeuristicLab.Collections;22 using System; 23 23 using HeuristicLab.Core.Views; 24 24 using HeuristicLab.MainForm; 25 using System;26 using System.Collections.Generic;27 using System.Drawing;28 using System.Linq;29 using System.Windows.Forms;30 using System.Windows.Forms.DataVisualization.Charting;31 25 32 26 namespace HeuristicLab.Analysis.Views { … … 34 28 [Content(typeof(DataTable), true)] 35 29 public partial class DataTableView : NamedItemView, IConfigureableView { 36 protected List<Series> invisibleSeries;37 protected Dictionary<IObservableList<double>, DataRow> valuesRowsTable;38 30 39 31 public new DataTable Content { … … 44 36 public DataTableView() { 45 37 InitializeComponent(); 46 valuesRowsTable = new Dictionary<IObservableList<double>, DataRow>();47 invisibleSeries = new List<Series>();48 chart.CustomizeAllChartAreas();49 chart.ChartAreas[0].CursorX.Interval = 1;50 38 } 51 52 #region Event Handler Registration53 protected override void DeregisterContentEvents() {54 foreach (DataRow row in Content.Rows)55 DeregisterDataRowEvents(row);56 Content.VisualPropertiesChanged -= new EventHandler(Content_VisualPropertiesChanged);57 Content.Rows.ItemsAdded -= new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsAdded);58 Content.Rows.ItemsRemoved -= new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsRemoved);59 Content.Rows.ItemsReplaced -= new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsReplaced);60 Content.Rows.CollectionReset -= new CollectionItemsChangedEventHandler<DataRow>(Rows_CollectionReset);61 base.DeregisterContentEvents();62 }63 protected override void RegisterContentEvents() {64 base.RegisterContentEvents();65 Content.VisualPropertiesChanged += new EventHandler(Content_VisualPropertiesChanged);66 Content.Rows.ItemsAdded += new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsAdded);67 Content.Rows.ItemsRemoved += new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsRemoved);68 Content.Rows.ItemsReplaced += new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsReplaced);69 Content.Rows.CollectionReset += new CollectionItemsChangedEventHandler<DataRow>(Rows_CollectionReset);70 }71 72 protected virtual void RegisterDataRowEvents(DataRow row) {73 row.NameChanged += new EventHandler(Row_NameChanged);74 row.VisualPropertiesChanged += new EventHandler(Row_VisualPropertiesChanged);75 valuesRowsTable.Add(row.Values, row);76 row.Values.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded);77 row.Values.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved);78 row.Values.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced);79 row.Values.ItemsMoved += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved);80 row.Values.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset);81 }82 protected virtual void DeregisterDataRowEvents(DataRow row) {83 row.Values.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded);84 row.Values.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved);85 row.Values.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced);86 row.Values.ItemsMoved -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved);87 row.Values.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset);88 valuesRowsTable.Remove(row.Values);89 row.VisualPropertiesChanged -= new EventHandler(Row_VisualPropertiesChanged);90 row.NameChanged -= new EventHandler(Row_NameChanged);91 }92 #endregion93 39 94 40 protected override void OnContentChanged() { 95 41 base.OnContentChanged(); 96 invisibleSeries.Clear(); 97 chart.Titles[0].Text = string.Empty; 98 chart.ChartAreas[0].AxisX.Title = string.Empty; 99 chart.ChartAreas[0].AxisY.Title = string.Empty; 100 chart.ChartAreas[0].AxisY2.Title = string.Empty; 101 chart.Series.Clear(); 102 if (Content != null) { 103 chart.Titles[0].Text = Content.Name; 104 AddDataRows(Content.Rows); 105 ConfigureChartArea(chart.ChartAreas[0]); 106 RecalculateAxesScale(chart.ChartAreas[0]); 107 } 42 chart.Content = Content; 108 43 } 109 44 … … 113 48 } 114 49 115 public void ShowConfiguration() {116 if (Content != null) {117 using (var dialog = new DataTableVisualPropertiesDialog(Content)) {118 dialog.ShowDialog(this);119 }120 } else MessageBox.Show("Nothing to configure.");121 }122 protected virtual void AddDataRows(IEnumerable<DataRow> rows) {123 foreach (var row in rows) {124 RegisterDataRowEvents(row);125 var series = new Series(row.Name);126 if (row.VisualProperties.DisplayName.Trim() != String.Empty) series.LegendText = row.VisualProperties.DisplayName;127 else series.LegendText = row.Name;128 ConfigureSeries(series, row);129 FillSeriesWithRowValues(series, row);130 chart.Series.Add(series);131 }132 ConfigureChartArea(chart.ChartAreas[0]);133 RecalculateAxesScale(chart.ChartAreas[0]);134 UpdateYCursorInterval();135 }136 137 protected virtual void RemoveDataRows(IEnumerable<DataRow> rows) {138 foreach (var row in rows) {139 DeregisterDataRowEvents(row);140 Series series = chart.Series[row.Name];141 chart.Series.Remove(series);142 if (invisibleSeries.Contains(series))143 invisibleSeries.Remove(series);144 }145 RecalculateAxesScale(chart.ChartAreas[0]);146 }147 148 private void ConfigureSeries(Series series, DataRow row) {149 RemoveCustomPropertyIfExists(series, "PointWidth");150 series.BorderWidth = 1;151 series.BorderDashStyle = ChartDashStyle.Solid;152 series.BorderColor = Color.Empty;153 154 if (row.VisualProperties.Color != Color.Empty)155 series.Color = row.VisualProperties.Color;156 else series.Color = Color.Empty;157 series.IsVisibleInLegend = row.VisualProperties.IsVisibleInLegend;158 159 switch (row.VisualProperties.ChartType) {160 case DataRowVisualProperties.DataRowChartType.Line:161 series.ChartType = SeriesChartType.FastLine;162 series.BorderWidth = row.VisualProperties.LineWidth;163 series.BorderDashStyle = ConvertLineStyle(row.VisualProperties.LineStyle);164 break;165 case DataRowVisualProperties.DataRowChartType.Bars:166 // Bar is incompatible with anything but Bar and StackedBar*167 if (!chart.Series.Any(x => x.ChartType != SeriesChartType.Bar && x.ChartType != SeriesChartType.StackedBar && x.ChartType != SeriesChartType.StackedBar100))168 series.ChartType = SeriesChartType.Bar;169 else {170 series.ChartType = SeriesChartType.FastPoint; //default171 row.VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Points;172 }173 break;174 case DataRowVisualProperties.DataRowChartType.Columns:175 series.ChartType = SeriesChartType.Column;176 break;177 case DataRowVisualProperties.DataRowChartType.Points:178 series.ChartType = SeriesChartType.FastPoint;179 break;180 case DataRowVisualProperties.DataRowChartType.Histogram:181 series.ChartType = SeriesChartType.Column;182 series.SetCustomProperty("PointWidth", "1");183 if (!series.Color.IsEmpty && series.Color.GetBrightness() < 0.25)184 series.BorderColor = Color.White;185 else series.BorderColor = Color.Black;186 break;187 case DataRowVisualProperties.DataRowChartType.StepLine:188 series.ChartType = SeriesChartType.StepLine;189 series.BorderWidth = row.VisualProperties.LineWidth;190 series.BorderDashStyle = ConvertLineStyle(row.VisualProperties.LineStyle);191 break;192 default:193 series.ChartType = SeriesChartType.FastPoint;194 break;195 }196 series.YAxisType = row.VisualProperties.SecondYAxis ? AxisType.Secondary : AxisType.Primary;197 series.XAxisType = row.VisualProperties.SecondXAxis ? AxisType.Secondary : AxisType.Primary;198 if (row.VisualProperties.DisplayName.Trim() != String.Empty) series.LegendText = row.VisualProperties.DisplayName;199 else series.LegendText = row.Name;200 201 string xAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.XAxisTitle)202 ? "X"203 : Content.VisualProperties.XAxisTitle;204 string yAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.YAxisTitle)205 ? "Y"206 : Content.VisualProperties.YAxisTitle;207 series.ToolTip =208 series.LegendText + Environment.NewLine +209 xAxisTitle + " = " + "#INDEX," + Environment.NewLine +210 yAxisTitle + " = " + "#VAL";211 }212 213 private void ConfigureChartArea(ChartArea area) {214 if (Content.VisualProperties.TitleFont != null) chart.Titles[0].Font = Content.VisualProperties.TitleFont;215 if (!Content.VisualProperties.TitleColor.IsEmpty) chart.Titles[0].ForeColor = Content.VisualProperties.TitleColor;216 chart.Titles[0].Text = Content.VisualProperties.Title;217 218 if (Content.VisualProperties.AxisTitleFont != null) area.AxisX.TitleFont = Content.VisualProperties.AxisTitleFont;219 if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisX.TitleForeColor = Content.VisualProperties.AxisTitleColor;220 area.AxisX.Title = Content.VisualProperties.XAxisTitle;221 222 if (Content.VisualProperties.AxisTitleFont != null) area.AxisX2.TitleFont = Content.VisualProperties.AxisTitleFont;223 if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisX2.TitleForeColor = Content.VisualProperties.AxisTitleColor;224 area.AxisX2.Title = Content.VisualProperties.SecondXAxisTitle;225 226 if (Content.VisualProperties.AxisTitleFont != null) area.AxisY.TitleFont = Content.VisualProperties.AxisTitleFont;227 if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisY.TitleForeColor = Content.VisualProperties.AxisTitleColor;228 area.AxisY.Title = Content.VisualProperties.YAxisTitle;229 230 if (Content.VisualProperties.AxisTitleFont != null) area.AxisY2.TitleFont = Content.VisualProperties.AxisTitleFont;231 if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisY2.TitleForeColor = Content.VisualProperties.AxisTitleColor;232 area.AxisY2.Title = Content.VisualProperties.SecondYAxisTitle;233 234 area.AxisX.IsLogarithmic = Content.VisualProperties.XAxisLogScale;235 area.AxisX2.IsLogarithmic = Content.VisualProperties.SecondXAxisLogScale;236 area.AxisY.IsLogarithmic = Content.VisualProperties.YAxisLogScale;237 area.AxisY2.IsLogarithmic = Content.VisualProperties.SecondYAxisLogScale;238 }239 240 private void RecalculateAxesScale(ChartArea area) {241 // Reset the axes bounds so that RecalculateAxesScale() will assign new bounds242 foreach (Axis a in area.Axes) {243 a.Minimum = double.NaN;244 a.Maximum = double.NaN;245 }246 area.RecalculateAxesScale();247 area.AxisX.IsMarginVisible = false;248 area.AxisX2.IsMarginVisible = false;249 250 if (!Content.VisualProperties.XAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.XAxisMinimumFixedValue)) area.AxisX.Minimum = Content.VisualProperties.XAxisMinimumFixedValue;251 if (!Content.VisualProperties.XAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.XAxisMaximumFixedValue)) area.AxisX.Maximum = Content.VisualProperties.XAxisMaximumFixedValue;252 if (!Content.VisualProperties.SecondXAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.SecondXAxisMinimumFixedValue)) area.AxisX2.Minimum = Content.VisualProperties.SecondXAxisMinimumFixedValue;253 if (!Content.VisualProperties.SecondXAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.SecondXAxisMaximumFixedValue)) area.AxisX2.Maximum = Content.VisualProperties.SecondXAxisMaximumFixedValue;254 if (!Content.VisualProperties.YAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.YAxisMinimumFixedValue)) area.AxisY.Minimum = Content.VisualProperties.YAxisMinimumFixedValue;255 if (!Content.VisualProperties.YAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.YAxisMaximumFixedValue)) area.AxisY.Maximum = Content.VisualProperties.YAxisMaximumFixedValue;256 if (!Content.VisualProperties.SecondYAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.SecondYAxisMinimumFixedValue)) area.AxisY2.Minimum = Content.VisualProperties.SecondYAxisMinimumFixedValue;257 if (!Content.VisualProperties.SecondYAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.SecondYAxisMaximumFixedValue)) area.AxisY2.Maximum = Content.VisualProperties.SecondYAxisMaximumFixedValue;258 if (area.AxisX.Minimum >= area.AxisX.Maximum) area.AxisX.Maximum = area.AxisX.Minimum + 1;259 if (area.AxisX2.Minimum >= area.AxisX2.Maximum) area.AxisX2.Maximum = area.AxisX2.Minimum + 1;260 if (area.AxisY.Minimum >= area.AxisY.Maximum) area.AxisY.Maximum = area.AxisY.Minimum + 1;261 if (area.AxisY2.Minimum >= area.AxisY2.Maximum) area.AxisY2.Maximum = area.AxisY2.Minimum + 1;262 }263 264 protected virtual void UpdateYCursorInterval() {265 double interestingValuesRange = (266 from series in chart.Series267 where series.Enabled268 let values = (from point in series.Points269 where !point.IsEmpty270 select point.YValues[0]).DefaultIfEmpty(1.0)271 let range = values.Max() - values.Min()272 where range > 0.0273 select range274 ).DefaultIfEmpty(1.0).Min();275 276 double digits = (int)Math.Log10(interestingValuesRange) - 3;277 double yZoomInterval = Math.Pow(10, digits);278 this.chart.ChartAreas[0].CursorY.Interval = yZoomInterval;279 }280 281 #region Event Handlers282 50 #region Content Event Handlers 283 51 protected override void Content_NameChanged(object sender, EventArgs e) { … … 285 53 Invoke(new EventHandler(Content_NameChanged), sender, e); 286 54 else { 287 chart.Titles[0].Text= Content.Name;55 Content.VisualProperties.Title = Content.Name; 288 56 base.Content_NameChanged(sender, e); 289 }290 }291 private void Content_VisualPropertiesChanged(object sender, EventArgs e) {292 if (InvokeRequired)293 Invoke(new EventHandler(Content_VisualPropertiesChanged), sender, e);294 else {295 ConfigureChartArea(chart.ChartAreas[0]);296 RecalculateAxesScale(chart.ChartAreas[0]); // axes min/max could have changed297 }298 }299 #endregion300 #region Rows Event Handlers301 private void Rows_ItemsAdded(object sender, CollectionItemsChangedEventArgs<DataRow> e) {302 if (InvokeRequired)303 Invoke(new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsAdded), sender, e);304 else {305 AddDataRows(e.Items);306 }307 }308 private void Rows_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<DataRow> e) {309 if (InvokeRequired)310 Invoke(new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsRemoved), sender, e);311 else {312 RemoveDataRows(e.Items);313 }314 }315 private void Rows_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<DataRow> e) {316 if (InvokeRequired)317 Invoke(new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsReplaced), sender, e);318 else {319 RemoveDataRows(e.OldItems);320 AddDataRows(e.Items);321 }322 }323 private void Rows_CollectionReset(object sender, CollectionItemsChangedEventArgs<DataRow> e) {324 if (InvokeRequired)325 Invoke(new CollectionItemsChangedEventHandler<DataRow>(Rows_CollectionReset), sender, e);326 else {327 RemoveDataRows(e.OldItems);328 AddDataRows(e.Items);329 }330 }331 #endregion332 #region Row Event Handlers333 private void Row_VisualPropertiesChanged(object sender, EventArgs e) {334 if (InvokeRequired)335 Invoke(new EventHandler(Row_VisualPropertiesChanged), sender, e);336 else {337 DataRow row = (DataRow)sender;338 Series series = chart.Series[row.Name];339 series.Points.Clear();340 ConfigureSeries(series, row);341 FillSeriesWithRowValues(series, row);342 RecalculateAxesScale(chart.ChartAreas[0]);343 }344 }345 private void Row_NameChanged(object sender, EventArgs e) {346 if (InvokeRequired)347 Invoke(new EventHandler(Row_NameChanged), sender, e);348 else {349 DataRow row = (DataRow)sender;350 chart.Series[row.Name].Name = row.Name;351 }352 }353 #endregion354 #region Values Event Handlers355 private void Values_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {356 if (InvokeRequired)357 Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded), sender, e);358 else {359 DataRow row = null;360 valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);361 if (row != null) {362 Series rowSeries = chart.Series[row.Name];363 if (!invisibleSeries.Contains(rowSeries)) {364 rowSeries.Points.Clear();365 FillSeriesWithRowValues(rowSeries, row);366 RecalculateAxesScale(chart.ChartAreas[0]);367 UpdateYCursorInterval();368 }369 }370 }371 }372 private void Values_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {373 if (InvokeRequired)374 Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved), sender, e);375 else {376 DataRow row = null;377 valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);378 if (row != null) {379 Series rowSeries = chart.Series[row.Name];380 if (!invisibleSeries.Contains(rowSeries)) {381 rowSeries.Points.Clear();382 FillSeriesWithRowValues(rowSeries, row);383 RecalculateAxesScale(chart.ChartAreas[0]);384 UpdateYCursorInterval();385 }386 }387 }388 }389 private void Values_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {390 if (InvokeRequired)391 Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced), sender, e);392 else {393 DataRow row = null;394 valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);395 if (row != null) {396 Series rowSeries = chart.Series[row.Name];397 if (!invisibleSeries.Contains(rowSeries)) {398 if (row.VisualProperties.ChartType == DataRowVisualProperties.DataRowChartType.Histogram) {399 rowSeries.Points.Clear();400 FillSeriesWithRowValues(rowSeries, row);401 } else {402 foreach (IndexedItem<double> item in e.Items) {403 if (IsInvalidValue(item.Value))404 rowSeries.Points[item.Index].IsEmpty = true;405 else {406 rowSeries.Points[item.Index].YValues = new double[] { item.Value };407 rowSeries.Points[item.Index].IsEmpty = false;408 }409 }410 }411 RecalculateAxesScale(chart.ChartAreas[0]);412 UpdateYCursorInterval();413 }414 }415 }416 }417 private void Values_ItemsMoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {418 if (InvokeRequired)419 Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved), sender, e);420 else {421 DataRow row = null;422 valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);423 if (row != null) {424 Series rowSeries = chart.Series[row.Name];425 if (!invisibleSeries.Contains(rowSeries)) {426 rowSeries.Points.Clear();427 FillSeriesWithRowValues(rowSeries, row);428 RecalculateAxesScale(chart.ChartAreas[0]);429 UpdateYCursorInterval();430 }431 }432 }433 }434 435 private void Values_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {436 if (InvokeRequired)437 Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset), sender, e);438 else {439 DataRow row = null;440 valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);441 if (row != null) {442 Series rowSeries = chart.Series[row.Name];443 if (!invisibleSeries.Contains(rowSeries)) {444 rowSeries.Points.Clear();445 FillSeriesWithRowValues(rowSeries, row);446 RecalculateAxesScale(chart.ChartAreas[0]);447 UpdateYCursorInterval();448 }449 }450 }451 }452 #endregion453 #endregion454 455 #region Chart Event Handlers456 private void chart_MouseDown(object sender, MouseEventArgs e) {457 HitTestResult result = chart.HitTest(e.X, e.Y);458 if (result.ChartElementType == ChartElementType.LegendItem) {459 ToggleSeriesVisible(result.Series);460 }461 }462 private void chart_MouseMove(object sender, MouseEventArgs e) {463 HitTestResult result = chart.HitTest(e.X, e.Y);464 if (result.ChartElementType == ChartElementType.LegendItem)465 this.Cursor = Cursors.Hand;466 else467 this.Cursor = Cursors.Default;468 }469 private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {470 foreach (LegendItem legendItem in e.LegendItems) {471 var series = chart.Series[legendItem.SeriesName];472 if (series != null) {473 bool seriesIsInvisible = invisibleSeries.Contains(series);474 foreach (LegendCell cell in legendItem.Cells) {475 cell.ForeColor = seriesIsInvisible ? Color.Gray : Color.Black;476 }477 }478 57 } 479 58 } 480 59 #endregion 481 60 482 private void ToggleSeriesVisible(Series series) { 483 if (!invisibleSeries.Contains(series)) { 484 series.Points.Clear(); 485 invisibleSeries.Add(series); 486 } else { 487 invisibleSeries.Remove(series); 488 if (Content != null) { 489 490 var row = (from r in Content.Rows 491 where r.Name == series.Name 492 select r).Single(); 493 FillSeriesWithRowValues(series, row); 494 this.chart.Legends[series.Legend].ForeColor = Color.Black; 495 RecalculateAxesScale(chart.ChartAreas[0]); 496 UpdateYCursorInterval(); 497 } 498 } 61 public void ShowConfiguration() { 62 chart.ShowConfiguration(); 499 63 } 500 501 private void FillSeriesWithRowValues(Series series, DataRow row) {502 switch (row.VisualProperties.ChartType) {503 case DataRowVisualProperties.DataRowChartType.Histogram:504 CalculateHistogram(series, row);505 break;506 default: {507 bool yLogarithmic = series.YAxisType == AxisType.Primary508 ? Content.VisualProperties.YAxisLogScale509 : Content.VisualProperties.SecondYAxisLogScale;510 bool xLogarithmic = series.XAxisType == AxisType.Primary511 ? Content.VisualProperties.XAxisLogScale512 : Content.VisualProperties.SecondXAxisLogScale;513 for (int i = 0; i < row.Values.Count; i++) {514 var value = row.Values[i];515 var point = new DataPoint();516 point.XValue = row.VisualProperties.StartIndexZero && !xLogarithmic ? i : i + 1;517 if (IsInvalidValue(value) || (yLogarithmic && value <= 0))518 point.IsEmpty = true;519 else520 point.YValues = new double[] { value };521 series.Points.Add(point);522 }523 }524 break;525 }526 }527 528 protected virtual void CalculateHistogram(Series series, DataRow row) {529 series.Points.Clear();530 if (!row.Values.Any()) return;531 int bins = row.VisualProperties.Bins;532 533 double minValue = row.Values.Min();534 double maxValue = row.Values.Max();535 double intervalWidth = (maxValue - minValue) / bins;536 if (intervalWidth < 0) return;537 if (intervalWidth == 0) {538 series.Points.AddXY(minValue, row.Values.Count);539 return;540 }541 542 if (!row.VisualProperties.ExactBins) {543 intervalWidth = HumanRoundRange(intervalWidth);544 minValue = Math.Floor(minValue / intervalWidth) * intervalWidth;545 maxValue = Math.Ceiling(maxValue / intervalWidth) * intervalWidth;546 }547 548 double intervalCenter = intervalWidth / 2;549 550 double min = 0.0, max = 0.0;551 if (!Double.IsNaN(Content.VisualProperties.XAxisMinimumFixedValue) && !Content.VisualProperties.XAxisMinimumAuto)552 min = Content.VisualProperties.XAxisMinimumFixedValue;553 else min = minValue;554 if (!Double.IsNaN(Content.VisualProperties.XAxisMaximumFixedValue) && !Content.VisualProperties.XAxisMaximumAuto)555 max = Content.VisualProperties.XAxisMaximumFixedValue;556 else max = maxValue + intervalWidth;557 558 double axisInterval = intervalWidth / row.VisualProperties.ScaleFactor;559 560 var area = chart.ChartAreas[0];561 area.AxisX.Interval = axisInterval;562 563 series.SetCustomProperty("PointWidth", "1"); // 0.8 is the default value564 565 // get the range or intervals which define the grouping of the frequency values566 var doubleRange = DoubleRange(min, max, intervalWidth).Skip(1).ToList();567 568 // aggregate the row values by unique key and frequency value569 var valueFrequencies = (from v in row.Values570 where !IsInvalidValue(v)571 orderby v572 group v by v into g573 select new Tuple<double, double>(g.First(), g.Count())).ToList();574 575 // shift the chart to the left so the bars are placed on the intervals576 if (valueFrequencies.First().Item1 < doubleRange.First())577 series.Points.Add(new DataPoint(min - intervalWidth, 0));578 579 // add data points580 int j = 0;581 foreach (var d in doubleRange) {582 double sum = 0.0;583 // sum the frequency values that fall within the same interval584 while (j < valueFrequencies.Count && valueFrequencies[j].Item1 < d) {585 sum += valueFrequencies[j].Item2;586 ++j;587 }588 string xAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.XAxisTitle)589 ? "X"590 : Content.VisualProperties.XAxisTitle;591 string yAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.YAxisTitle)592 ? "Y"593 : Content.VisualProperties.YAxisTitle;594 series.Points.Add(new DataPoint(d - intervalCenter, sum) {595 ToolTip =596 xAxisTitle + ": [" + (d - intervalWidth) + "-" + d + ")" + Environment.NewLine +597 yAxisTitle + ": " + sum598 });599 }600 }601 602 #region Helpers603 public static IEnumerable<double> DoubleRange(double min, double max, double step) {604 double i;605 for (i = min; i <= max; i += step)606 yield return i;607 608 if (i != max + step)609 yield return i;610 }611 612 protected void RemoveCustomPropertyIfExists(Series series, string property) {613 if (series.IsCustomPropertySet(property)) series.DeleteCustomProperty(property);614 }615 616 private double HumanRoundRange(double range) {617 double base10 = Math.Pow(10.0, Math.Floor(Math.Log10(range)));618 double rounding = range / base10;619 if (rounding <= 1.5) rounding = 1;620 else if (rounding <= 2.25) rounding = 2;621 else if (rounding <= 3.75) rounding = 2.5;622 else if (rounding <= 7.5) rounding = 5;623 else rounding = 10;624 return rounding * base10;625 }626 627 private double HumanRoundMax(double max) {628 double base10;629 if (max > 0) base10 = Math.Pow(10.0, Math.Floor(Math.Log10(max)));630 else base10 = Math.Pow(10.0, Math.Ceiling(Math.Log10(-max)));631 double rounding = (max > 0) ? base10 : -base10;632 while (rounding < max) rounding += base10;633 return rounding;634 }635 636 private ChartDashStyle ConvertLineStyle(DataRowVisualProperties.DataRowLineStyle dataRowLineStyle) {637 switch (dataRowLineStyle) {638 case DataRowVisualProperties.DataRowLineStyle.Dash:639 return ChartDashStyle.Dash;640 case DataRowVisualProperties.DataRowLineStyle.DashDot:641 return ChartDashStyle.DashDot;642 case DataRowVisualProperties.DataRowLineStyle.DashDotDot:643 return ChartDashStyle.DashDotDot;644 case DataRowVisualProperties.DataRowLineStyle.Dot:645 return ChartDashStyle.Dot;646 case DataRowVisualProperties.DataRowLineStyle.NotSet:647 return ChartDashStyle.NotSet;648 case DataRowVisualProperties.DataRowLineStyle.Solid:649 return ChartDashStyle.Solid;650 default:651 return ChartDashStyle.NotSet;652 }653 }654 655 protected static bool IsInvalidValue(double x) {656 return double.IsNaN(x) || x < (double)decimal.MinValue || x > (double)decimal.MaxValue;657 }658 #endregion659 64 } 660 65 }
Note: See TracChangeset
for help on using the changeset viewer.