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