Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
01/23/17 16:11:02 (7 years ago)
Author:
abeham
Message:

#2457: updated branch to trunk

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  
    11#region License Information
    22/* HeuristicLab
    3  * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
     3 * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
    44 *
    55 * This file is part of HeuristicLab.
     
    2020#endregion
    2121
    22 using HeuristicLab.Collections;
     22using System;
    2323using HeuristicLab.Core.Views;
    2424using 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;
    3125
    3226namespace HeuristicLab.Analysis.Views {
     
    3428  [Content(typeof(DataTable), true)]
    3529  public partial class DataTableView : NamedItemView, IConfigureableView {
    36     protected List<Series> invisibleSeries;
    37     protected Dictionary<IObservableList<double>, DataRow> valuesRowsTable;
    3830
    3931    public new DataTable Content {
     
    4436    public DataTableView() {
    4537      InitializeComponent();
    46       valuesRowsTable = new Dictionary<IObservableList<double>, DataRow>();
    47       invisibleSeries = new List<Series>();
    48       chart.CustomizeAllChartAreas();
    49       chart.ChartAreas[0].CursorX.Interval = 1;
    5038    }
    51 
    52     #region Event Handler Registration
    53     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     #endregion
    9339
    9440    protected override void OnContentChanged() {
    9541      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;
    10843    }
    10944
     
    11348    }
    11449
    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; //default
    171             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 bounds
    242       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.Series
    267         where series.Enabled
    268         let values = (from point in series.Points
    269                       where !point.IsEmpty
    270                       select point.YValues[0]).DefaultIfEmpty(1.0)
    271         let range = values.Max() - values.Min()
    272         where range > 0.0
    273         select range
    274         ).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 Handlers
    28250    #region Content Event Handlers
    28351    protected override void Content_NameChanged(object sender, EventArgs e) {
     
    28553        Invoke(new EventHandler(Content_NameChanged), sender, e);
    28654      else {
    287         chart.Titles[0].Text = Content.Name;
     55        Content.VisualProperties.Title = Content.Name;
    28856        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 changed
    297       }
    298     }
    299     #endregion
    300     #region Rows Event Handlers
    301     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     #endregion
    332     #region Row Event Handlers
    333     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     #endregion
    354     #region Values Event Handlers
    355     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     #endregion
    453     #endregion
    454 
    455     #region Chart Event Handlers
    456     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       else
    467         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         }
    47857      }
    47958    }
    48059    #endregion
    48160
    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();
    49963    }
    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.Primary
    508                                   ? Content.VisualProperties.YAxisLogScale
    509                                   : Content.VisualProperties.SecondYAxisLogScale;
    510             bool xLogarithmic = series.XAxisType == AxisType.Primary
    511                                   ? Content.VisualProperties.XAxisLogScale
    512                                   : 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               else
    520                 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 value
    564 
    565       // get the range or intervals which define the grouping of the frequency values
    566       var doubleRange = DoubleRange(min, max, intervalWidth).Skip(1).ToList();
    567 
    568       // aggregate the row values by unique key and frequency value
    569       var valueFrequencies = (from v in row.Values
    570                               where !IsInvalidValue(v)
    571                               orderby v
    572                               group v by v into g
    573                               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 intervals
    576       if (valueFrequencies.First().Item1 < doubleRange.First())
    577         series.Points.Add(new DataPoint(min - intervalWidth, 0));
    578 
    579       // add data points
    580       int j = 0;
    581       foreach (var d in doubleRange) {
    582         double sum = 0.0;
    583         // sum the frequency values that fall within the same interval
    584         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 + ": " + sum
    598         });
    599       }
    600     }
    601 
    602     #region Helpers
    603     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     #endregion
    65964  }
    66065}
Note: See TracChangeset for help on using the changeset viewer.