Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
12/02/16 13:06:49 (8 years ago)
Author:
pfleck
Message:

#2713 Moved the charting logic out of DataTableView and ScatterPlotView into new DataTableControl and ScatterPlotControl.
This way, the charts can be reused without the name-textbox and description from the NamedItemView.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/sources/HeuristicLab.Analysis.Views/3.3/DataTableView.cs

    r14438 r14439  
    2121
    2222using 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;
    2923using HeuristicLab.Core.Views;
    3024using HeuristicLab.MainForm;
     
    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;
    50       chart.ContextMenuStrip.Items.Add(configureToolStripMenuItem);
    5138    }
    52 
    53     #region Event Handler Registration
    54     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     #endregion
    9439
    9540    protected override void OnContentChanged() {
    9641      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;
    11043    }
    11144
     
    11548    }
    11649
    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; //default
    173             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 bounds
    245       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.Series
    270         where series.Enabled
    271         let values = (from point in series.Points
    272                       where !point.IsEmpty
    273                       select point.YValues[0]).DefaultIfEmpty(1.0)
    274         let range = values.Max() - values.Min()
    275         where range > 0.0
    276         select range
    277         ).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 Handlers
    28550    #region Content Event Handlers
    28651    protected override void Content_NameChanged(object sender, EventArgs e) {
     
    28853        Invoke(new EventHandler(Content_NameChanged), sender, e);
    28954      else {
    290         chart.Titles[0].Text = Content.Name;
    291         chart.Titles[0].Visible = !string.IsNullOrEmpty(Content.Name);
     55        Content.VisualProperties.Title = Content.Name;
    29256        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 changed
    301       }
    302     }
    303     #endregion
    304     #region Rows Event Handlers
    305     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     #endregion
    336     #region Row Event Handlers
    337     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     #endregion
    358     #region Values Event Handlers
    359     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     #endregion
    457     private void configureToolStripMenuItem_Click(object sender, EventArgs e) {
    458       ShowConfiguration();
    459     }
    460     #endregion
    461 
    462     #region Chart Event Handlers
    463     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       else
    474         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         }
    48557      }
    48658    }
    48759    #endregion
    48860
    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();
    50663    }
    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.Primary
    515                                   ? Content.VisualProperties.YAxisLogScale
    516                                   : Content.VisualProperties.SecondYAxisLogScale;
    517             bool xLogarithmic = series.XAxisType == AxisType.Primary
    518                                   ? Content.VisualProperties.XAxisLogScale
    519                                   : 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               else
    527                 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 value
    571 
    572       // get the range or intervals which define the grouping of the frequency values
    573       var doubleRange = DoubleRange(min, max, intervalWidth).Skip(1).ToList();
    574 
    575       // aggregate the row values by unique key and frequency value
    576       var valueFrequencies = (from v in row.Values
    577                               where !IsInvalidValue(v)
    578                               orderby v
    579                               group v by v into g
    580                               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 intervals
    583       if (valueFrequencies.First().Item1 < doubleRange.First())
    584         series.Points.Add(new DataPoint(min - intervalWidth, 0));
    585 
    586       // add data points
    587       int j = 0;
    588       foreach (var d in doubleRange) {
    589         double sum = 0.0;
    590         // sum the frequency values that fall within the same interval
    591         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 + ": " + sum
    605         });
    606       }
    607     }
    608 
    609     #region Helpers
    610     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     #endregion
    66664  }
    66765}
Note: See TracChangeset for help on using the changeset viewer.