You've already forked linux-packaging-mono
Rewrite with hard-coded offsets into the PE file format to discern if a binary is PE32 or PE32+, and then to determine if it contains a "CLR Data Directory" entry that looks valid. Tested with PE32 and PE32+ compiled Mono binaries, PE32 and PE32+ native binaries, and a random assortment of garbage files. Former-commit-id: 9e7ac86ec84f653a2f79b87183efd5b0ebda001b
3496 lines
114 KiB
C#
3496 lines
114 KiB
C#
//-------------------------------------------------------------
|
||
// <copyright company=’Microsoft Corporation’>
|
||
// Copyright © Microsoft Corporation. All Rights Reserved.
|
||
// </copyright>
|
||
//-------------------------------------------------------------
|
||
// @owner=alexgor, deliant
|
||
//=================================================================
|
||
// File: DataManipulator.cs
|
||
//
|
||
// Namespace: DataVisualization.Charting
|
||
//
|
||
// Classes: DataManipulator, IDataPointFilter
|
||
//
|
||
// Purpose: DataManipulator class exposes to the user methods
|
||
// to perform data filtering, grouping, inserting
|
||
// empty points, sorting and exporting data.
|
||
//
|
||
// It also expose financial and statistical formulas
|
||
// through the DataFormula base class.
|
||
//
|
||
// Reviewed: AG - Jul 31, 2002;
|
||
// GS - Aug 7, 2002
|
||
// AG - Microsoft 15, 2007
|
||
//
|
||
//===================================================================
|
||
|
||
#region Used namespaces
|
||
|
||
using System;
|
||
using System.Collections;
|
||
using System.Collections.Specialized;
|
||
using System.Collections.Generic;
|
||
using System.ComponentModel;
|
||
using System.ComponentModel.Design;
|
||
using System.Drawing;
|
||
using System.Data;
|
||
using System.Drawing.Drawing2D;
|
||
using System.Drawing.Design;
|
||
|
||
#if Microsoft_CONTROL
|
||
using System.Windows.Forms.DataVisualization.Charting;
|
||
#else
|
||
using System.Web;
|
||
using System.Web.UI;
|
||
using System.Web.UI.DataVisualization.Charting;
|
||
#endif
|
||
|
||
|
||
#endregion
|
||
|
||
#if Microsoft_CONTROL
|
||
namespace System.Windows.Forms.DataVisualization.Charting
|
||
#else
|
||
namespace System.Web.UI.DataVisualization.Charting
|
||
#endif
|
||
{
|
||
#region Data manipulation enumerations
|
||
|
||
/// <summary>
|
||
/// Grouping functions types
|
||
/// </summary>
|
||
internal enum GroupingFunction
|
||
{
|
||
/// <summary>
|
||
/// Not defined
|
||
/// </summary>
|
||
None,
|
||
/// <summary>
|
||
/// Minimum value of the group
|
||
/// </summary>
|
||
Min,
|
||
/// <summary>
|
||
/// Maximum value of the group
|
||
/// </summary>
|
||
Max,
|
||
/// <summary>
|
||
/// Average value of the group
|
||
/// </summary>
|
||
Ave,
|
||
/// <summary>
|
||
/// Total of all values of the group
|
||
/// </summary>
|
||
Sum,
|
||
/// <summary>
|
||
/// Value of the first point in the group
|
||
/// </summary>
|
||
First,
|
||
/// <summary>
|
||
/// Value of the last point in the group
|
||
/// </summary>
|
||
Last,
|
||
/// <summary>
|
||
/// Value of the center point in the group
|
||
/// </summary>
|
||
Center,
|
||
/// <summary>
|
||
/// High, Low, Open, Close values in the group
|
||
/// </summary>
|
||
HiLoOpCl,
|
||
/// <summary>
|
||
/// High, Low values in the group
|
||
/// </summary>
|
||
HiLo,
|
||
/// <summary>
|
||
/// Number of points in the group
|
||
/// </summary>
|
||
Count,
|
||
/// <summary>
|
||
/// Number of unique points in the group
|
||
/// </summary>
|
||
DistinctCount,
|
||
/// <summary>
|
||
/// Variance of points in the group
|
||
/// </summary>
|
||
Variance,
|
||
/// <summary>
|
||
/// Deviation of points in the group
|
||
/// </summary>
|
||
Deviation
|
||
}
|
||
|
||
/// <summary>
|
||
/// An enumeration of units of measurement for intervals.
|
||
/// </summary>
|
||
public enum IntervalType
|
||
{
|
||
/// <summary>
|
||
/// Interval in numbers.
|
||
/// </summary>
|
||
Number,
|
||
/// <summary>
|
||
/// Interval in years.
|
||
/// </summary>
|
||
Years,
|
||
/// <summary>
|
||
/// Interval in months.
|
||
/// </summary>
|
||
Months,
|
||
/// <summary>
|
||
/// Interval in weeks.
|
||
/// </summary>
|
||
Weeks,
|
||
/// <summary>
|
||
/// Interval in days.
|
||
/// </summary>
|
||
Days,
|
||
/// <summary>
|
||
/// Interval in hours.
|
||
/// </summary>
|
||
Hours,
|
||
/// <summary>
|
||
/// Interval in minutes.
|
||
/// </summary>
|
||
Minutes,
|
||
/// <summary>
|
||
/// Interval in seconds.
|
||
/// </summary>
|
||
Seconds,
|
||
/// <summary>
|
||
/// Interval in milliseconds.
|
||
/// </summary>
|
||
Milliseconds
|
||
}
|
||
|
||
/// <summary>
|
||
/// An enumeration of units of measurement for date ranges.
|
||
/// </summary>
|
||
public enum DateRangeType
|
||
{
|
||
/// <summary>
|
||
/// Range defined in years.
|
||
/// </summary>
|
||
Year,
|
||
/// <summary>
|
||
/// Range defined in months.
|
||
/// </summary>
|
||
Month,
|
||
/// <summary>
|
||
/// Range defined in days of week.
|
||
/// </summary>
|
||
DayOfWeek,
|
||
/// <summary>
|
||
/// Range defined in days of month.
|
||
/// </summary>
|
||
DayOfMonth,
|
||
/// <summary>
|
||
/// Range defined in hours.
|
||
/// </summary>
|
||
Hour,
|
||
/// <summary>
|
||
/// Range defined in minutes.
|
||
/// </summary>
|
||
Minute
|
||
}
|
||
|
||
/// <summary>
|
||
/// An enumeration of methods of comparison.
|
||
/// </summary>
|
||
public enum CompareMethod
|
||
{
|
||
/// <summary>
|
||
/// One value is more than the other value.
|
||
/// </summary>
|
||
MoreThan,
|
||
/// <summary>
|
||
/// One value is less than the other value.
|
||
/// </summary>
|
||
LessThan,
|
||
/// <summary>
|
||
/// One value is equal the other value.
|
||
/// </summary>
|
||
EqualTo,
|
||
/// <summary>
|
||
/// One value is more or equal to the other value.
|
||
/// </summary>
|
||
MoreThanOrEqualTo,
|
||
/// <summary>
|
||
/// One value is less or equal to the other value.
|
||
/// </summary>
|
||
LessThanOrEqualTo,
|
||
/// <summary>
|
||
/// One value is not equal to the other value.
|
||
/// </summary>
|
||
NotEqualTo
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Data points filtering inteface
|
||
|
||
/// <summary>
|
||
/// The IDataPointFilter interface is used for filtering series data points.
|
||
/// </summary>
|
||
#if ASPPERM_35
|
||
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
|
||
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
|
||
#endif
|
||
public interface IDataPointFilter
|
||
{
|
||
/// <summary>
|
||
/// Checks if the specified data point must be filtered.
|
||
/// </summary>
|
||
/// <param name="point">Data point object.</param>
|
||
/// <param name="series">Series of the point.</param>
|
||
/// <param name="pointIndex">Index of the point in the series.</param>
|
||
/// <returns>True if point must be removed</returns>
|
||
bool FilterDataPoint(DataPoint point, Series series, int pointIndex);
|
||
}
|
||
|
||
#endregion
|
||
|
||
/// <summary>
|
||
/// The DataManipulator class is used at runtime to perform data manipulation
|
||
/// operations, and is exposed via the DataManipulator property of the
|
||
/// root Chart object.
|
||
/// </summary>
|
||
#if ASPPERM_35
|
||
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
|
||
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
|
||
#endif
|
||
public class DataManipulator : DataFormula
|
||
{
|
||
#region Fields
|
||
|
||
// Indicates that filtering do not remove points, just mark them as empty
|
||
private bool _filterSetEmptyPoints = false;
|
||
|
||
// Indicates that points that match the criteria must be filtered out
|
||
private bool _filterMatchedPoints = true;
|
||
|
||
#endregion // Fields
|
||
|
||
#region Data manipulator helper functions
|
||
|
||
/// <summary>
|
||
/// Helper function that converts one series or a comma separated
|
||
/// list of series names into the Series array.
|
||
/// </summary>
|
||
/// <param name="obj">Series or string of series names.</param>
|
||
/// <param name="createNew">If series with this name do not exist - create new.</param>
|
||
/// <returns>Array of series.</returns>
|
||
internal Series[] ConvertToSeriesArray(object obj, bool createNew)
|
||
{
|
||
Series[] array = null;
|
||
|
||
if(obj == null)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
// Parameter is one series
|
||
if(obj.GetType() == typeof(Series))
|
||
{
|
||
array = new Series[1];
|
||
array[0] = (Series)obj;
|
||
}
|
||
|
||
// Parameter is a string (comma separated series names)
|
||
else if(obj.GetType() == typeof(string))
|
||
{
|
||
string series = (string)obj;
|
||
int index = 0;
|
||
|
||
// "*" means process all series from the collection
|
||
if(series == "*")
|
||
{
|
||
// Create array of series
|
||
array = new Series[Common.DataManager.Series.Count];
|
||
|
||
// Add all series from the collection
|
||
foreach(Series s in Common.DataManager.Series)
|
||
{
|
||
array[index] = s;
|
||
++index;
|
||
}
|
||
}
|
||
|
||
// Comma separated list
|
||
else if(series.Length > 0)
|
||
{
|
||
// Replace commas in value string
|
||
series = series.Replace("\\,", "\\x45");
|
||
series = series.Replace("\\=", "\\x46");
|
||
|
||
// Split string by comma
|
||
string[] seriesNames = series.Split(',');
|
||
|
||
// Create array of series
|
||
array = new Series[seriesNames.Length];
|
||
|
||
// Find series by name
|
||
foreach(string s in seriesNames)
|
||
{
|
||
// Put pack a comma character
|
||
string seriesName = s.Replace("\\x45", ",");
|
||
seriesName = seriesName.Replace("\\x46", "=");
|
||
|
||
try
|
||
{
|
||
array[index] = Common.DataManager.Series[seriesName.Trim()];
|
||
}
|
||
catch(System.Exception)
|
||
{
|
||
if(createNew)
|
||
{
|
||
Series newSeries = new Series(seriesName.Trim());
|
||
Common.DataManager.Series.Add(newSeries);
|
||
array[index] = newSeries;
|
||
}
|
||
else
|
||
{
|
||
throw;
|
||
}
|
||
}
|
||
|
||
++index;
|
||
}
|
||
}
|
||
}
|
||
|
||
return array;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Public constructor
|
||
/// </summary>
|
||
public DataManipulator()
|
||
{
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Series points sorting methods
|
||
|
||
/// <summary>
|
||
/// Sort series data points in specified order.
|
||
/// </summary>
|
||
/// <param name="pointSortOrder">Sorting order.</param>
|
||
/// <param name="sortBy">Value to sort by.</param>
|
||
/// <param name="series">Series array to sort.</param>
|
||
private void Sort(PointSortOrder pointSortOrder, string sortBy, Series[] series)
|
||
{
|
||
// Check arguments
|
||
if (sortBy == null)
|
||
throw new ArgumentNullException("sortBy");
|
||
if (series == null)
|
||
throw new ArgumentNullException("series");
|
||
|
||
// Check array of series
|
||
if(series.Length == 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// Sort series
|
||
DataPointComparer comparer = new DataPointComparer(series[0], pointSortOrder, sortBy);
|
||
this.Sort(comparer, series);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Sort series data points in specified order.
|
||
/// </summary>
|
||
/// <param name="comparer">Comparing interface.</param>
|
||
/// <param name="series">Series array to sort.</param>
|
||
private void Sort(IComparer<DataPoint> comparer, Series[] series)
|
||
{
|
||
// Check arguments
|
||
if (comparer == null)
|
||
throw new ArgumentNullException("comparer");
|
||
if (series == null)
|
||
throw new ArgumentNullException("series");
|
||
|
||
//**************************************************
|
||
//** Check array of series
|
||
//**************************************************
|
||
if(series.Length == 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
//**************************************************
|
||
//** If we sorting more than one series
|
||
//**************************************************
|
||
if(series.Length > 1)
|
||
{
|
||
// Check if series X values are aligned
|
||
this.CheckXValuesAlignment(series);
|
||
|
||
// Apply points indexes to the first series
|
||
int pointIndex = 0;
|
||
foreach(DataPoint point in series[0].Points)
|
||
{
|
||
point["_Index"] = pointIndex.ToString(System.Globalization.CultureInfo.InvariantCulture);
|
||
++pointIndex;
|
||
}
|
||
}
|
||
|
||
//**************************************************
|
||
//** Sort first series
|
||
//**************************************************
|
||
series[0].Sort(comparer);
|
||
|
||
//**************************************************
|
||
//** If we sorting more than one series
|
||
//**************************************************
|
||
if(series.Length > 1)
|
||
{
|
||
// Sort other series (depending on the first)
|
||
int toIndex = 0;
|
||
int fromIndex = 0;
|
||
foreach(DataPoint point in series[0].Points)
|
||
{
|
||
// Move point from index is stored in point attribute (as index before sorting)
|
||
fromIndex = int.Parse(point["_Index"], System.Globalization.CultureInfo.InvariantCulture);
|
||
|
||
// Move points in series
|
||
for(int seriesIndex = 1; seriesIndex < series.Length; seriesIndex++)
|
||
{
|
||
series[seriesIndex].Points.Insert(toIndex, series[seriesIndex].Points[toIndex + fromIndex]);
|
||
}
|
||
|
||
// Increase move point to index
|
||
++toIndex;
|
||
}
|
||
|
||
// Remove extra points from series
|
||
for(int seriesIndex = 1; seriesIndex < series.Length; seriesIndex++)
|
||
{
|
||
while(series[seriesIndex].Points.Count > series[0].Points.Count)
|
||
{
|
||
series[seriesIndex].Points.RemoveAt(series[seriesIndex].Points.Count - 1);
|
||
}
|
||
}
|
||
|
||
//**************************************************
|
||
//** Remove points index attribute
|
||
//**************************************************
|
||
foreach(DataPoint point in series[0].Points)
|
||
{
|
||
point.DeleteCustomProperty("_Index");
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Series points sorting overloaded methods
|
||
|
||
/// <summary>
|
||
/// Sort the series' data points in specified order.
|
||
/// </summary>
|
||
/// <param name="pointSortOrder">Sorting order.</param>
|
||
/// <param name="sortBy">Value to sort by.</param>
|
||
/// <param name="seriesName">Comma separated series names to sort.</param>
|
||
public void Sort(PointSortOrder pointSortOrder, string sortBy, string seriesName)
|
||
{
|
||
// Check arguments
|
||
if (seriesName == null)
|
||
throw new ArgumentNullException("seriesName");
|
||
|
||
Sort(pointSortOrder, sortBy, ConvertToSeriesArray(seriesName, false));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Sort the series' data points in specified order.
|
||
/// </summary>
|
||
/// <param name="pointSortOrder">Sorting order.</param>
|
||
/// <param name="series">Series to sort.</param>
|
||
public void Sort(PointSortOrder pointSortOrder, Series series)
|
||
{
|
||
// Check arguments
|
||
if (series == null)
|
||
throw new ArgumentNullException("series");
|
||
|
||
Sort(pointSortOrder, "Y", ConvertToSeriesArray(series, false));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Sort the series' data points in specified order.
|
||
/// </summary>
|
||
/// <param name="pointSortOrder">Sorting order.</param>
|
||
/// <param name="seriesName">Comma separated series names to sort.</param>
|
||
public void Sort(PointSortOrder pointSortOrder, string seriesName)
|
||
{
|
||
// Check arguments
|
||
if (seriesName == null)
|
||
throw new ArgumentNullException("seriesName");
|
||
|
||
Sort(pointSortOrder, "Y", ConvertToSeriesArray(seriesName, false));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Sort the series' data points in specified order.
|
||
/// </summary>
|
||
/// <param name="pointSortOrder">Sorting order.</param>
|
||
/// <param name="sortBy">Value to sort by.</param>
|
||
/// <param name="series">Series to sort.</param>
|
||
public void Sort(PointSortOrder pointSortOrder, string sortBy, Series series)
|
||
{
|
||
// Check arguments
|
||
if (series == null)
|
||
throw new ArgumentNullException("series");
|
||
|
||
Sort(pointSortOrder, sortBy, ConvertToSeriesArray(series, false));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Sort the series' data points in specified order.
|
||
/// </summary>
|
||
/// <param name="comparer">IComparer interface.</param>
|
||
/// <param name="series">Series to sort.</param>
|
||
public void Sort(IComparer<DataPoint> comparer, Series series)
|
||
{
|
||
// Check arguments - comparer is checked in the private override of Sort
|
||
if (series == null)
|
||
throw new ArgumentNullException("series");
|
||
|
||
Sort(comparer, ConvertToSeriesArray(series, false));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Sort the series' data points in specified order.
|
||
/// </summary>
|
||
/// <param name="comparer">Comparing interface.</param>
|
||
/// <param name="seriesName">Comma separated series names to sort.</param>
|
||
public void Sort(IComparer<DataPoint> comparer, string seriesName)
|
||
{
|
||
// Check arguments - comparer is checked in the private override of Sort
|
||
if (seriesName == null)
|
||
throw new ArgumentNullException("seriesName");
|
||
|
||
Sort(comparer, ConvertToSeriesArray(seriesName, false));
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Insert empty data points method
|
||
|
||
/// <summary>
|
||
/// Insert empty data points using specified interval.
|
||
/// </summary>
|
||
/// <param name="interval">Interval size.</param>
|
||
/// <param name="intervalType">Interval type.</param>
|
||
/// <param name="intervalOffset">Interval offset size.</param>
|
||
/// <param name="intervalOffsetType">Interval offset type.</param>
|
||
/// <param name="fromXValue">Check intervals from this X value.</param>
|
||
/// <param name="toXValue">Check intervals until this X value.</param>
|
||
/// <param name="series">Series array.</param>
|
||
private void InsertEmptyPoints(
|
||
double interval,
|
||
IntervalType intervalType,
|
||
double intervalOffset,
|
||
IntervalType intervalOffsetType,
|
||
double fromXValue,
|
||
double toXValue,
|
||
Series[] series)
|
||
{
|
||
// Check the arguments
|
||
if (interval <= 0)
|
||
throw new ArgumentOutOfRangeException("interval");
|
||
|
||
//**************************************************
|
||
//** Automaticly detect minimum and maximum values
|
||
//**************************************************
|
||
double fromX = Math.Min(fromXValue, toXValue);
|
||
double toX = Math.Max(fromXValue, toXValue);
|
||
bool fromIsNaN = double.IsNaN(fromX);
|
||
bool toIsNaN = double.IsNaN(toX);
|
||
foreach(Series ser in series)
|
||
{
|
||
if(ser.Points.Count >= 1)
|
||
{
|
||
if(toIsNaN)
|
||
{
|
||
if(double.IsNaN(toX))
|
||
{
|
||
toX = ser.Points[ser.Points.Count - 1].XValue;
|
||
}
|
||
else
|
||
{
|
||
toX = Math.Max(toX, ser.Points[ser.Points.Count - 1].XValue);
|
||
}
|
||
}
|
||
if(fromIsNaN)
|
||
{
|
||
if(double.IsNaN(fromX))
|
||
{
|
||
fromX = ser.Points[0].XValue;
|
||
}
|
||
else
|
||
{
|
||
fromX = Math.Min(fromX, ser.Points[0].XValue);
|
||
}
|
||
}
|
||
if(fromX > toX)
|
||
{
|
||
double tempValue = fromX;
|
||
fromX = toX;
|
||
toX = tempValue;
|
||
}
|
||
}
|
||
}
|
||
|
||
//**************************************************
|
||
//** Automaticly adjust the beginning interval and
|
||
//** offset
|
||
//**************************************************
|
||
double nonAdjustedFromX = fromX;
|
||
fromX = ChartHelper.AlignIntervalStart(fromX, interval, ConvertIntervalType(intervalType));
|
||
|
||
// Add offset to the start position
|
||
if( intervalOffset != 0 )
|
||
{
|
||
fromX = fromX + ChartHelper.GetIntervalSize(fromX, intervalOffset, ConvertIntervalType(intervalOffsetType), null, 0, DateTimeIntervalType.Number, true, false);
|
||
}
|
||
|
||
|
||
//**************************************************
|
||
//** Loop through all series
|
||
//**************************************************
|
||
foreach(Series ser in series)
|
||
{
|
||
//**************************************************
|
||
//** Loop through all data points
|
||
//**************************************************
|
||
int numberOfPoints = 0;
|
||
int lastInsertPoint = 0;
|
||
double currentPointValue = fromX;
|
||
while(currentPointValue <= toX)
|
||
{
|
||
//**************************************************
|
||
//** Check that X value is in range
|
||
//**************************************************
|
||
bool outOfRange = false;
|
||
if(double.IsNaN(fromXValue) && currentPointValue < nonAdjustedFromX ||
|
||
!double.IsNaN(fromXValue) && currentPointValue < fromXValue)
|
||
{
|
||
outOfRange = true;
|
||
}
|
||
else if(currentPointValue > toXValue)
|
||
{
|
||
outOfRange = true;
|
||
}
|
||
|
||
|
||
// Current X value is in range of points values
|
||
if(!outOfRange)
|
||
{
|
||
//**************************************************
|
||
//** Find required X value
|
||
//**************************************************
|
||
int insertPosition = lastInsertPoint;
|
||
for(int pointIndex = lastInsertPoint; pointIndex < ser.Points.Count; pointIndex++)
|
||
{
|
||
// Value was found
|
||
if(ser.Points[pointIndex].XValue == currentPointValue)
|
||
{
|
||
insertPosition = -1;
|
||
break;
|
||
}
|
||
|
||
// Save point index where we should insert new empty point
|
||
if(ser.Points[pointIndex].XValue > currentPointValue)
|
||
{
|
||
insertPosition = pointIndex;
|
||
break;
|
||
}
|
||
|
||
// Insert as last point
|
||
if(pointIndex == (ser.Points.Count - 1))
|
||
{
|
||
insertPosition = ser.Points.Count;
|
||
}
|
||
}
|
||
|
||
//**************************************************
|
||
//** Required value was not found - insert empty data point
|
||
//**************************************************
|
||
if(insertPosition != -1)
|
||
{
|
||
lastInsertPoint = insertPosition;
|
||
++numberOfPoints;
|
||
DataPoint dataPoint = new DataPoint(ser);
|
||
dataPoint.XValue = currentPointValue;
|
||
dataPoint.IsEmpty = true;
|
||
ser.Points.Insert(insertPosition, dataPoint);
|
||
}
|
||
}
|
||
|
||
//**************************************************
|
||
//** Determine next required data point
|
||
//**************************************************
|
||
currentPointValue += ChartHelper.GetIntervalSize(currentPointValue,
|
||
interval,
|
||
ConvertIntervalType(intervalType));
|
||
|
||
|
||
//**************************************************
|
||
//** Check if we exceed number of empty points
|
||
//** we can add.
|
||
//**************************************************
|
||
if(numberOfPoints > 1000)
|
||
{
|
||
currentPointValue = toX + 1;
|
||
continue;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Helper function which converts IntervalType enumeration
|
||
/// into DateTimeIntervalType enumeration.
|
||
/// </summary>
|
||
/// <param name="type">Interval type value.</param>
|
||
/// <returns>Date time interval type value.</returns>
|
||
private DateTimeIntervalType ConvertIntervalType(IntervalType type)
|
||
{
|
||
switch(type)
|
||
{
|
||
case(IntervalType.Milliseconds):
|
||
return DateTimeIntervalType.Milliseconds;
|
||
case(IntervalType.Seconds):
|
||
return DateTimeIntervalType.Seconds;
|
||
case(IntervalType.Days):
|
||
return DateTimeIntervalType.Days;
|
||
case(IntervalType.Hours):
|
||
return DateTimeIntervalType.Hours;
|
||
case(IntervalType.Minutes):
|
||
return DateTimeIntervalType.Minutes;
|
||
case(IntervalType.Months):
|
||
return DateTimeIntervalType.Months;
|
||
case(IntervalType.Number):
|
||
return DateTimeIntervalType.Number;
|
||
case(IntervalType.Weeks):
|
||
return DateTimeIntervalType.Weeks;
|
||
case(IntervalType.Years):
|
||
return DateTimeIntervalType.Years;
|
||
}
|
||
|
||
return DateTimeIntervalType.Auto;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Insert empty data points overloaded methods
|
||
|
||
/// <summary>
|
||
/// Insert empty data points using the specified interval.
|
||
/// </summary>
|
||
/// <param name="interval">Interval size.</param>
|
||
/// <param name="intervalType">Interval type.</param>
|
||
/// <param name="series">Series to insert the empty points.</param>
|
||
public void InsertEmptyPoints(
|
||
double interval,
|
||
IntervalType intervalType,
|
||
Series series)
|
||
{
|
||
InsertEmptyPoints(interval, intervalType, 0, IntervalType.Number, series);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Insert empty data points using the specified interval.
|
||
/// </summary>
|
||
/// <param name="interval">Interval size.</param>
|
||
/// <param name="intervalType">Interval type.</param>
|
||
/// <param name="seriesName">Name of series to insert the empty points.</param>
|
||
public void InsertEmptyPoints(
|
||
double interval,
|
||
IntervalType intervalType,
|
||
string seriesName)
|
||
{
|
||
InsertEmptyPoints(interval, intervalType, 0, IntervalType.Number, seriesName);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Insert empty data points using the specified interval.
|
||
/// </summary>
|
||
/// <param name="interval">Interval size.</param>
|
||
/// <param name="intervalType">Interval type.</param>
|
||
/// <param name="intervalOffset">Interval offset size.</param>
|
||
/// <param name="intervalOffsetType">Interval offset type.</param>
|
||
/// <param name="seriesName">Name of series to insert the empty points.</param>
|
||
public void InsertEmptyPoints(
|
||
double interval,
|
||
IntervalType intervalType,
|
||
double intervalOffset,
|
||
IntervalType intervalOffsetType,
|
||
string seriesName)
|
||
{
|
||
InsertEmptyPoints(interval, intervalType, intervalOffset, intervalOffsetType, double.NaN, double.NaN, seriesName);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Insert empty data points using the specified interval.
|
||
/// </summary>
|
||
/// <param name="interval">Interval size.</param>
|
||
/// <param name="intervalType">Interval type.</param>
|
||
/// <param name="intervalOffset">Interval offset size.</param>
|
||
/// <param name="intervalOffsetType">Interval offset type.</param>
|
||
/// <param name="series">Series to insert the empty points.</param>
|
||
public void InsertEmptyPoints(
|
||
double interval,
|
||
IntervalType intervalType,
|
||
double intervalOffset,
|
||
IntervalType intervalOffsetType,
|
||
Series series)
|
||
{
|
||
InsertEmptyPoints(interval, intervalType, intervalOffset, intervalOffsetType, double.NaN, double.NaN, series);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Insert empty data points using the specified interval.
|
||
/// </summary>
|
||
/// <param name="interval">Interval size.</param>
|
||
/// <param name="intervalType">Interval type.</param>
|
||
/// <param name="intervalOffset">Interval offset size.</param>
|
||
/// <param name="intervalOffsetType">Interval offset type.</param>
|
||
/// <param name="fromXValue">Check intervals from this X value.</param>
|
||
/// <param name="toXValue">Check intervals until this X value.</param>
|
||
/// <param name="seriesName">Name of series to insert the empty points.</param>
|
||
public void InsertEmptyPoints(
|
||
double interval,
|
||
IntervalType intervalType,
|
||
double intervalOffset,
|
||
IntervalType intervalOffsetType,
|
||
double fromXValue,
|
||
double toXValue,
|
||
string seriesName)
|
||
{
|
||
// Check arguments
|
||
if (seriesName == null)
|
||
throw new ArgumentNullException("seriesName");
|
||
|
||
InsertEmptyPoints(
|
||
interval,
|
||
intervalType,
|
||
intervalOffset,
|
||
intervalOffsetType,
|
||
fromXValue,
|
||
toXValue,
|
||
ConvertToSeriesArray(seriesName, false));
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Insert empty data points using the specified interval.
|
||
/// </summary>
|
||
/// <param name="interval">Interval size.</param>
|
||
/// <param name="intervalType">Interval type.</param>
|
||
/// <param name="intervalOffset">Interval offset size.</param>
|
||
/// <param name="intervalOffsetType">Interval offset type.</param>
|
||
/// <param name="fromXValue">Check intervals from this X value.</param>
|
||
/// <param name="toXValue">Check intervals until this X value.</param>
|
||
/// <param name="series">Series to insert the empty points.</param>
|
||
public void InsertEmptyPoints(
|
||
double interval,
|
||
IntervalType intervalType,
|
||
double intervalOffset,
|
||
IntervalType intervalOffsetType,
|
||
double fromXValue,
|
||
double toXValue,
|
||
Series series)
|
||
{
|
||
// Check arguments
|
||
if (series == null)
|
||
throw new ArgumentNullException("series");
|
||
|
||
InsertEmptyPoints(
|
||
interval,
|
||
intervalType,
|
||
intervalOffset,
|
||
intervalOffsetType,
|
||
fromXValue,
|
||
toXValue,
|
||
ConvertToSeriesArray(series, false));
|
||
}
|
||
|
||
|
||
#endregion
|
||
|
||
#region Series data exporting methods
|
||
|
||
/// <summary>
|
||
/// Export series data into the DataSet object.
|
||
/// </summary>
|
||
/// <param name="series">Array of series which should be exported.</param>
|
||
/// <returns>Data set object with series data.</returns>
|
||
internal DataSet ExportSeriesValues(Series[] series)
|
||
{
|
||
//*****************************************************
|
||
//** Create DataSet object
|
||
//*****************************************************
|
||
DataSet dataSet = new DataSet();
|
||
dataSet.Locale = System.Globalization.CultureInfo.CurrentCulture;
|
||
// If input series are specified
|
||
if(series != null)
|
||
{
|
||
// Export each series in the loop
|
||
foreach(Series ser in series)
|
||
{
|
||
|
||
//*****************************************************
|
||
//** Check if all X values are zeros
|
||
//*****************************************************
|
||
bool zeroXValues = true;
|
||
foreach( DataPoint point in ser.Points )
|
||
{
|
||
if( point.XValue != 0.0 )
|
||
{
|
||
zeroXValues = false;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// Added 10 May 2005, DT - dataset after databinding
|
||
// to string x value returns X as indexes
|
||
if (zeroXValues && ser.XValueType == ChartValueType.String)
|
||
{
|
||
zeroXValues = false;
|
||
}
|
||
|
||
//*****************************************************
|
||
//** Create new table for the series
|
||
//*****************************************************
|
||
DataTable seriesTable = new DataTable(ser.Name);
|
||
seriesTable.Locale = System.Globalization.CultureInfo.CurrentCulture;
|
||
|
||
//*****************************************************
|
||
//** Add X column into data table schema
|
||
//*****************************************************
|
||
Type columnType = typeof(double);
|
||
if(ser.IsXValueDateTime())
|
||
{
|
||
columnType = typeof(DateTime);
|
||
}
|
||
else if(ser.XValueType == ChartValueType.String)
|
||
{
|
||
columnType = typeof(string);
|
||
}
|
||
seriesTable.Columns.Add("X", columnType);
|
||
|
||
|
||
//*****************************************************
|
||
//** Add Y column(s) into data table schema
|
||
//*****************************************************
|
||
columnType = typeof(double);
|
||
if(ser.IsYValueDateTime())
|
||
{
|
||
columnType = typeof(DateTime);
|
||
}
|
||
else if(ser.YValueType == ChartValueType.String)
|
||
{
|
||
columnType = typeof(string);
|
||
}
|
||
for(int yIndex = 0; yIndex < ser.YValuesPerPoint; yIndex++)
|
||
{
|
||
if(yIndex == 0)
|
||
{
|
||
seriesTable.Columns.Add("Y", columnType);
|
||
}
|
||
else
|
||
{
|
||
seriesTable.Columns.Add("Y" + (yIndex + 1).ToString(System.Globalization.CultureInfo.InvariantCulture), columnType);
|
||
}
|
||
}
|
||
|
||
|
||
//*****************************************************
|
||
//** Fill data table's rows
|
||
//*****************************************************
|
||
double pointIndex = 1.0;
|
||
foreach(DataPoint point in ser.Points)
|
||
{
|
||
if(!point.IsEmpty || !this.IsEmptyPointIgnored)
|
||
{
|
||
DataRow dataRow = seriesTable.NewRow();
|
||
|
||
// Set row X value
|
||
object xValue = point.XValue;
|
||
if(ser.IsXValueDateTime())
|
||
{
|
||
if (Double.IsNaN(point.XValue))
|
||
xValue = DBNull.Value;
|
||
else
|
||
xValue = DateTime.FromOADate(point.XValue);
|
||
}
|
||
else if(ser.XValueType == ChartValueType.String)
|
||
{
|
||
xValue = point.AxisLabel;
|
||
}
|
||
dataRow["X"] = (zeroXValues) ? pointIndex : xValue;
|
||
|
||
// Set row Y value(s)
|
||
for(int yIndex = 0; yIndex < ser.YValuesPerPoint; yIndex++)
|
||
{
|
||
object yValue = point.YValues[yIndex];
|
||
if(!point.IsEmpty)
|
||
{
|
||
if(ser.IsYValueDateTime())
|
||
{
|
||
if (Double.IsNaN(point.YValues[yIndex]))
|
||
xValue = DBNull.Value;
|
||
else
|
||
yValue = DateTime.FromOADate(point.YValues[yIndex]);
|
||
}
|
||
else if(ser.YValueType == ChartValueType.String)
|
||
{
|
||
yValue = point.AxisLabel;
|
||
}
|
||
}
|
||
else if(!this.IsEmptyPointIgnored)
|
||
{
|
||
// Special handling of empty points
|
||
yValue = DBNull.Value;
|
||
}
|
||
|
||
if(yIndex == 0)
|
||
{
|
||
dataRow["Y"] = yValue;
|
||
}
|
||
else
|
||
{
|
||
dataRow["Y" + (yIndex + 1).ToString(System.Globalization.CultureInfo.InvariantCulture)] = yValue;
|
||
}
|
||
}
|
||
|
||
// Add row to the table
|
||
seriesTable.Rows.Add(dataRow);
|
||
|
||
++pointIndex;
|
||
}
|
||
}
|
||
|
||
// Accept changes
|
||
seriesTable.AcceptChanges();
|
||
|
||
//*****************************************************
|
||
//** Add data table into the data set
|
||
//*****************************************************
|
||
dataSet.Tables.Add(seriesTable);
|
||
}
|
||
}
|
||
|
||
return dataSet;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Series data exporting overloaded methods
|
||
|
||
/// <summary>
|
||
/// Export all series from the collection into the DataSet object.
|
||
/// </summary>
|
||
/// <returns>Dataset object with series data.</returns>
|
||
public DataSet ExportSeriesValues()
|
||
{
|
||
return ExportSeriesValues("*");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Export series data into the DataSet object.
|
||
/// </summary>
|
||
/// <param name="seriesNames">Comma separated list of series names to be exported.</param>
|
||
/// <returns>Dataset object with series data.</returns>
|
||
public DataSet ExportSeriesValues(string seriesNames)
|
||
{
|
||
// Check arguments
|
||
if (seriesNames == null)
|
||
throw new ArgumentNullException(seriesNames);
|
||
|
||
return ExportSeriesValues(ConvertToSeriesArray(seriesNames, false));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Export series data into the DataSet object.
|
||
/// </summary>
|
||
/// <param name="series">Series to be exported.</param>
|
||
/// <returns>Dataset object with series data.</returns>
|
||
public DataSet ExportSeriesValues(Series series)
|
||
{
|
||
// Check arguments
|
||
if (series == null)
|
||
throw new ArgumentNullException("series");
|
||
|
||
return ExportSeriesValues(ConvertToSeriesArray(series, false));
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Filtering properties
|
||
|
||
/// <summary>
|
||
/// Gets or sets a flag which indicates whether points filtered by
|
||
/// the Filter or FilterTopN methods are removed or marked as empty.
|
||
/// If set to true, filtered points are marked as empty; otherwise they are removed.
|
||
/// This property defaults to be false.
|
||
/// </summary>
|
||
public bool FilterSetEmptyPoints
|
||
{
|
||
get
|
||
{
|
||
return _filterSetEmptyPoints;
|
||
}
|
||
set
|
||
{
|
||
_filterSetEmptyPoints = value;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Gets or sets a value that determines if points are filtered
|
||
/// if they match criteria that is specified in Filter method calls.
|
||
/// If set to true, points that match specified criteria are filtered.
|
||
/// If set to false, points that do not match the criteria are filtered.
|
||
/// This property defaults to be true.
|
||
/// </summary>
|
||
public bool FilterMatchedPoints
|
||
{
|
||
get
|
||
{
|
||
return _filterMatchedPoints;
|
||
}
|
||
set
|
||
{
|
||
_filterMatchedPoints = value;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Filtering methods
|
||
|
||
/// <summary>
|
||
/// Keeps only N top/bottom points of the series
|
||
/// </summary>
|
||
/// <param name="pointCount">Number of top/bottom points to return.</param>
|
||
/// <param name="inputSeries">Input series array.</param>
|
||
/// <param name="outputSeries">Output series array.</param>
|
||
/// <param name="usingValue">Defines which value of the point use in comparison (X, Y, Y2, ...).</param>
|
||
/// <param name="getTopValues">Indicate that N top values must be retrieved, otherwise N bottom values.</param>
|
||
private void FilterTopN(int pointCount,
|
||
Series[] inputSeries,
|
||
Series[] outputSeries,
|
||
string usingValue,
|
||
bool getTopValues)
|
||
{
|
||
// Check input/output series arrays
|
||
CheckSeriesArrays(inputSeries, outputSeries);
|
||
|
||
// Check input series alignment
|
||
CheckXValuesAlignment(inputSeries);
|
||
|
||
if(pointCount <= 0)
|
||
{
|
||
throw (new ArgumentOutOfRangeException("pointCount", SR.ExceptionDataManipulatorPointCountIsZero));
|
||
}
|
||
|
||
//**************************************************
|
||
//** Filter points in the first series and remove
|
||
//** in all
|
||
//**************************************************
|
||
|
||
// Define an output series array
|
||
Series[] output = new Series[inputSeries.Length];
|
||
for(int seriesIndex = 0; seriesIndex < inputSeries.Length; seriesIndex++)
|
||
{
|
||
output[seriesIndex] = inputSeries[seriesIndex];
|
||
if(outputSeries != null && outputSeries.Length > seriesIndex)
|
||
{
|
||
output[seriesIndex] = outputSeries[seriesIndex];
|
||
}
|
||
|
||
// Remove all points from the output series
|
||
if(output[seriesIndex] != inputSeries[seriesIndex])
|
||
{
|
||
output[seriesIndex].Points.Clear();
|
||
|
||
// Make sure there is enough Y values per point
|
||
output[seriesIndex].YValuesPerPoint = inputSeries[seriesIndex].YValuesPerPoint;
|
||
|
||
// Copy X values type
|
||
if(output[seriesIndex].XValueType == ChartValueType.Auto || output[seriesIndex].autoXValueType)
|
||
{
|
||
output[seriesIndex].XValueType = inputSeries[seriesIndex].XValueType;
|
||
output[seriesIndex].autoXValueType = true;
|
||
}
|
||
// Copy Y values type
|
||
if(output[seriesIndex].YValueType == ChartValueType.Auto || output[seriesIndex].autoYValueType)
|
||
{
|
||
output[seriesIndex].YValueType = inputSeries[seriesIndex].YValueType;
|
||
output[seriesIndex].autoYValueType = true;
|
||
}
|
||
|
||
// Copy input points into output
|
||
foreach(DataPoint point in inputSeries[seriesIndex].Points)
|
||
{
|
||
output[seriesIndex].Points.Add(point.Clone());
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
// No points to filter
|
||
if(inputSeries[0].Points.Count == 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
//**************************************************
|
||
//** Sort input data
|
||
//**************************************************
|
||
this.Sort((getTopValues) ? PointSortOrder.Descending : PointSortOrder.Ascending,
|
||
usingValue,
|
||
output);
|
||
|
||
//**************************************************
|
||
//** Get top/bottom points
|
||
//**************************************************
|
||
// Process all series
|
||
for(int seriesIndex = 0; seriesIndex < inputSeries.Length; seriesIndex++)
|
||
{
|
||
// Only keep N first points
|
||
while(output[seriesIndex].Points.Count > pointCount)
|
||
{
|
||
if(this.FilterSetEmptyPoints)
|
||
{
|
||
output[seriesIndex].Points[pointCount].IsEmpty = true;
|
||
++pointCount;
|
||
}
|
||
else
|
||
{
|
||
output[seriesIndex].Points.RemoveAt(pointCount);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Filter data points using IDataPointFilter interface
|
||
/// </summary>
|
||
/// <param name="filterInterface">Data points filtering interface.</param>
|
||
/// <param name="inputSeries">Input series array.</param>
|
||
/// <param name="outputSeries">Output series array.</param>
|
||
private void Filter(IDataPointFilter filterInterface,
|
||
Series[] inputSeries,
|
||
Series[] outputSeries)
|
||
{
|
||
//**************************************************
|
||
//** Check input/output series arrays
|
||
//**************************************************
|
||
CheckSeriesArrays(inputSeries, outputSeries);
|
||
|
||
CheckXValuesAlignment(inputSeries);
|
||
|
||
if(filterInterface == null)
|
||
{
|
||
throw(new ArgumentNullException("filterInterface"));
|
||
}
|
||
|
||
//**************************************************
|
||
//** Filter points in the first series and remove
|
||
//** in all
|
||
//**************************************************
|
||
|
||
// Define an output series array
|
||
Series[] output = new Series[inputSeries.Length];
|
||
for(int seriesIndex = 0; seriesIndex < inputSeries.Length; seriesIndex++)
|
||
{
|
||
output[seriesIndex] = inputSeries[seriesIndex];
|
||
if(outputSeries != null && outputSeries.Length > seriesIndex)
|
||
{
|
||
output[seriesIndex] = outputSeries[seriesIndex];
|
||
}
|
||
|
||
// Remove all points from the output series
|
||
if(output[seriesIndex] != inputSeries[seriesIndex])
|
||
{
|
||
output[seriesIndex].Points.Clear();
|
||
|
||
// Make sure there is enough Y values per point
|
||
output[seriesIndex].YValuesPerPoint = inputSeries[seriesIndex].YValuesPerPoint;
|
||
|
||
// Copy X values type
|
||
if(output[seriesIndex].XValueType == ChartValueType.Auto || output[seriesIndex].autoXValueType)
|
||
{
|
||
output[seriesIndex].XValueType = inputSeries[seriesIndex].XValueType;
|
||
output[seriesIndex].autoXValueType = true;
|
||
}
|
||
// Copy Y values type
|
||
if(output[seriesIndex].YValueType == ChartValueType.Auto || output[seriesIndex].autoYValueType)
|
||
{
|
||
output[seriesIndex].YValueType = inputSeries[seriesIndex].YValueType;
|
||
output[seriesIndex].autoYValueType = true;
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
// No points to filter
|
||
if(inputSeries[0].Points.Count == 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
//**************************************************
|
||
//** Loop through all points of the first input series
|
||
//**************************************************
|
||
int originalPointIndex = 0;
|
||
for(int pointIndex = 0; pointIndex < inputSeries[0].Points.Count; pointIndex++, originalPointIndex++)
|
||
{
|
||
bool pointRemoved = false;
|
||
|
||
// Check if point match the criteria
|
||
bool matchCriteria = filterInterface.FilterDataPoint(
|
||
inputSeries[0].Points[pointIndex],
|
||
inputSeries[0],
|
||
originalPointIndex) == this.FilterMatchedPoints;
|
||
|
||
|
||
// Process all series
|
||
for(int seriesIndex = 0; seriesIndex < inputSeries.Length; seriesIndex++)
|
||
{
|
||
bool seriesMatchCriteria = matchCriteria;
|
||
if(output[seriesIndex] != inputSeries[seriesIndex])
|
||
{
|
||
if(seriesMatchCriteria && !this.FilterSetEmptyPoints)
|
||
{
|
||
// Don't do anything...
|
||
seriesMatchCriteria = false;
|
||
}
|
||
else
|
||
{
|
||
// Copy point into the output series for all series
|
||
output[seriesIndex].Points.Add(inputSeries[seriesIndex].Points[pointIndex].Clone());
|
||
}
|
||
}
|
||
|
||
|
||
// If point match the criteria
|
||
if(seriesMatchCriteria)
|
||
{
|
||
// Set point's empty flag
|
||
if(this.FilterSetEmptyPoints)
|
||
{
|
||
output[seriesIndex].Points[pointIndex].IsEmpty = true;
|
||
for(int valueIndex = 0; valueIndex < output[seriesIndex].Points[pointIndex].YValues.Length; valueIndex++)
|
||
{
|
||
output[seriesIndex].Points[pointIndex].YValues[valueIndex] = 0.0;
|
||
}
|
||
}
|
||
|
||
// Remove point
|
||
else
|
||
{
|
||
output[seriesIndex].Points.RemoveAt(pointIndex);
|
||
pointRemoved = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Adjust index because of the removed point
|
||
if(pointRemoved)
|
||
{
|
||
--pointIndex;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Data point filter.
|
||
/// Filters points using element type and index
|
||
/// </summary>
|
||
private class PointElementFilter : IDataPointFilter
|
||
{
|
||
// Private fields
|
||
private DataManipulator _dataManipulator = null;
|
||
private DateRangeType _dateRange;
|
||
private int[] _rangeElements = null;
|
||
|
||
// Default constructor is not accesiable
|
||
private PointElementFilter()
|
||
{
|
||
}
|
||
|
||
/// <summary>
|
||
/// Public constructor.
|
||
/// </summary>
|
||
/// <param name="dataManipulator">Data manipulator object.</param>
|
||
/// <param name="dateRange">Range type.</param>
|
||
/// <param name="rangeElements">Range elements to filter.</param>
|
||
public PointElementFilter(DataManipulator dataManipulator, DateRangeType dateRange, string rangeElements)
|
||
{
|
||
this._dataManipulator = dataManipulator;
|
||
this._dateRange = dateRange;
|
||
this._rangeElements = dataManipulator.ConvertElementIndexesToArray(rangeElements);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Data points filtering method.
|
||
/// </summary>
|
||
/// <param name="point">Data point.</param>
|
||
/// <param name="series">Data point series.</param>
|
||
/// <param name="pointIndex">Data point index.</param>
|
||
/// <returns>Indicates that point should be filtered.</returns>
|
||
public bool FilterDataPoint(DataPoint point, Series series, int pointIndex)
|
||
{
|
||
return _dataManipulator.CheckFilterElementCriteria(
|
||
this._dateRange,
|
||
this._rangeElements,
|
||
point);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Data point filter.
|
||
/// Filters points using point values
|
||
/// </summary>
|
||
private class PointValueFilter : IDataPointFilter
|
||
{
|
||
// Private fields
|
||
private CompareMethod _compareMethod;
|
||
private string _usingValue;
|
||
private double _compareValue;
|
||
|
||
/// <summary>
|
||
/// Default constructor is not accessible
|
||
/// </summary>
|
||
private PointValueFilter()
|
||
{
|
||
}
|
||
|
||
/// <summary>
|
||
/// Public constructor.
|
||
/// </summary>
|
||
/// <param name="compareMethod">Comparing method.</param>
|
||
/// <param name="compareValue">Comparing constant.</param>
|
||
/// <param name="usingValue">Value used in comparison.</param>
|
||
public PointValueFilter(CompareMethod compareMethod,
|
||
double compareValue,
|
||
string usingValue)
|
||
{
|
||
this._compareMethod = compareMethod;
|
||
this._usingValue = usingValue;
|
||
this._compareValue = compareValue;
|
||
}
|
||
|
||
/// <summary>
|
||
/// IDataPointFilter interface method implementation
|
||
/// </summary>
|
||
/// <param name="point">Data point.</param>
|
||
/// <param name="series">Data point series.</param>
|
||
/// <param name="pointIndex">Data point index.</param>
|
||
/// <returns>Indicates that point should be filtered.</returns>
|
||
public bool FilterDataPoint(DataPoint point, Series series, int pointIndex)
|
||
{
|
||
// Check if point match the criteria
|
||
bool matchCriteria = false;
|
||
switch(_compareMethod)
|
||
{
|
||
case(CompareMethod.EqualTo):
|
||
matchCriteria = point.GetValueByName(_usingValue)
|
||
== _compareValue;
|
||
break;
|
||
case(CompareMethod.LessThan):
|
||
matchCriteria = point.GetValueByName(_usingValue)
|
||
< _compareValue;
|
||
break;
|
||
case(CompareMethod.LessThanOrEqualTo):
|
||
matchCriteria = point.GetValueByName(_usingValue)
|
||
<= _compareValue;
|
||
break;
|
||
case(CompareMethod.MoreThan):
|
||
matchCriteria = point.GetValueByName(_usingValue)
|
||
> _compareValue;
|
||
break;
|
||
case(CompareMethod.MoreThanOrEqualTo):
|
||
matchCriteria = point.GetValueByName(_usingValue)
|
||
>= _compareValue;
|
||
break;
|
||
case(CompareMethod.NotEqualTo):
|
||
matchCriteria = point.GetValueByName(_usingValue)
|
||
!= _compareValue;
|
||
break;
|
||
}
|
||
|
||
return matchCriteria;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Helper function to convert elements indexes from a string
|
||
/// into an array of integers
|
||
/// </summary>
|
||
/// <param name="rangeElements">Element indexes string. Ex:"3,5,6-9,15"</param>
|
||
/// <returns>Array of integer indexes.</returns>
|
||
private int[] ConvertElementIndexesToArray(string rangeElements)
|
||
{
|
||
// Split input string by comma
|
||
string[] indexes = rangeElements.Split(',');
|
||
|
||
// Check if there are items in the array
|
||
if(indexes.Length == 0)
|
||
{
|
||
throw (new ArgumentException(SR.ExceptionDataManipulatorIndexUndefined, "rangeElements"));
|
||
}
|
||
|
||
// Allocate memory for the result array
|
||
int[] result = new int[indexes.Length * 2];
|
||
|
||
// Process each element index
|
||
int index = 0;
|
||
foreach(string str in indexes)
|
||
{
|
||
// Check if it's a simple index or a range
|
||
if(str.IndexOf('-') != -1)
|
||
{
|
||
string[] rangeIndex = str.Split('-');
|
||
if(rangeIndex.Length == 2)
|
||
{
|
||
// Convert to integer
|
||
try
|
||
{
|
||
result[index] = Int32.Parse(rangeIndex[0], System.Globalization.CultureInfo.InvariantCulture);
|
||
result[index + 1] = Int32.Parse(rangeIndex[1], System.Globalization.CultureInfo.InvariantCulture);
|
||
|
||
if(result[index + 1] < result[index])
|
||
{
|
||
int temp = result[index];
|
||
result[index] = result[index + 1];
|
||
result[index + 1] = temp;
|
||
}
|
||
}
|
||
catch(System.Exception)
|
||
{
|
||
throw (new ArgumentException(SR.ExceptionDataManipulatorIndexFormatInvalid, "rangeElements"));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
throw (new ArgumentException(SR.ExceptionDataManipulatorIndexFormatInvalid, "rangeElements"));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Convert to integer
|
||
try
|
||
{
|
||
result[index] = Int32.Parse(str, System.Globalization.CultureInfo.InvariantCulture);
|
||
result[index + 1] = result[index];
|
||
}
|
||
catch(System.Exception)
|
||
{
|
||
throw (new ArgumentException(SR.ExceptionDataManipulatorIndexFormatInvalid, "rangeElements"));
|
||
}
|
||
}
|
||
|
||
index += 2;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Helper function, which checks if specified point matches the criteria
|
||
/// </summary>
|
||
/// <param name="dateRange">Element type.</param>
|
||
/// <param name="rangeElements">Array of element indexes ranges (pairs).</param>
|
||
/// <param name="point">Data point to check.</param>
|
||
/// <returns>True if point matches the criteria.</returns>
|
||
private bool CheckFilterElementCriteria(
|
||
DateRangeType dateRange,
|
||
int[] rangeElements,
|
||
DataPoint point)
|
||
{
|
||
// Conver X value to DateTime
|
||
DateTime dateTimeValue = DateTime.FromOADate(point.XValue);
|
||
|
||
for(int index = 0; index < rangeElements.Length; index += 2)
|
||
{
|
||
switch(dateRange)
|
||
{
|
||
case(DateRangeType.Year):
|
||
if(dateTimeValue.Year >= rangeElements[index] &&
|
||
dateTimeValue.Year <= rangeElements[index+1])
|
||
return true;
|
||
break;
|
||
case(DateRangeType.Month):
|
||
if(dateTimeValue.Month >= rangeElements[index] &&
|
||
dateTimeValue.Month <= rangeElements[index+1])
|
||
return true;
|
||
break;
|
||
case(DateRangeType.DayOfWeek):
|
||
if((int)dateTimeValue.DayOfWeek >= rangeElements[index] &&
|
||
(int)dateTimeValue.DayOfWeek <= rangeElements[index+1])
|
||
return true;
|
||
break;
|
||
case(DateRangeType.DayOfMonth):
|
||
if(dateTimeValue.Day >= rangeElements[index] &&
|
||
dateTimeValue.Day <= rangeElements[index+1])
|
||
return true;
|
||
break;
|
||
case(DateRangeType.Hour):
|
||
if(dateTimeValue.Hour >= rangeElements[index] &&
|
||
dateTimeValue.Hour <= rangeElements[index+1])
|
||
return true;
|
||
break;
|
||
case(DateRangeType.Minute):
|
||
if(dateTimeValue.Minute >= rangeElements[index] &&
|
||
dateTimeValue.Minute <= rangeElements[index+1])
|
||
return true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Filtering overloaded methods
|
||
|
||
/// <summary>
|
||
/// Filters a series' data points, either removing the specified points
|
||
/// or marking them as empty for the given date/time ranges.
|
||
/// </summary>
|
||
/// <param name="dateRange">Element type.</param>
|
||
/// <param name="rangeElements">Specifies the elements within the date/time range
|
||
/// (specified by the dateRange parameter) that will be filtered. Can be a single value (e.g. "7"),
|
||
/// comma-separated values (e.g. "5,6"), a range of values (e.g. 9-11),
|
||
/// or any variation thereof (e.g. "5,6,9-11").</param>
|
||
/// <param name="inputSeriesNames">Comma separated list of input series names.</param>
|
||
/// <param name="outputSeriesNames">Comma separated list of output series names, to store the output.</param>
|
||
public void Filter(DateRangeType dateRange,
|
||
string rangeElements,
|
||
string inputSeriesNames,
|
||
string outputSeriesNames)
|
||
{
|
||
// Check arguments
|
||
if (rangeElements == null)
|
||
throw new ArgumentNullException("rangeElements");
|
||
if (inputSeriesNames == null)
|
||
throw new ArgumentNullException("inputSeriesNames");
|
||
|
||
// Filter points using filtering interface
|
||
Filter(new PointElementFilter(this, dateRange, rangeElements),
|
||
ConvertToSeriesArray(inputSeriesNames, false),
|
||
ConvertToSeriesArray(outputSeriesNames, true));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Filters a series' data points, either removing the specified points
|
||
/// or marking them as empty for the given date/time ranges.
|
||
/// The Series object that is filtered is used to store the modified data.
|
||
/// </summary>
|
||
/// <param name="dateRange">Element type.</param>
|
||
/// <param name="rangeElements">Specifies the elements within the date/time range
|
||
/// (specified by the dateRange parameter) that will be filtered. Can be a single value (e.g. "7"),
|
||
/// comma-separated values (e.g. "5,6"), a range of values (e.g. 9-11),
|
||
/// or any variation thereof (e.g. "5,6,9-11").</param>
|
||
/// <param name="inputSeries">Input series.</param>
|
||
public void Filter(DateRangeType dateRange,
|
||
string rangeElements,
|
||
Series inputSeries)
|
||
{
|
||
// Check arguments
|
||
if (rangeElements == null)
|
||
throw new ArgumentNullException("rangeElements");
|
||
if (inputSeries == null)
|
||
throw new ArgumentNullException("inputSeries");
|
||
|
||
Filter(dateRange, rangeElements, inputSeries, null);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Filters a series' data points, either removing the specified points
|
||
/// or marking them as empty for the given date/time ranges.
|
||
/// </summary>
|
||
/// <param name="dateRange">Element type.</param>
|
||
/// <param name="rangeElements">Specifies the elements within the date/time range
|
||
/// (specified by the dateRange parameter) that will be filtered. Can be a single value (e.g. "7"),
|
||
/// comma-separated values (e.g. "5,6"), a range of values (e.g. 9-11),
|
||
/// or any variation thereof (e.g. "5,6,9-11").</param>
|
||
/// <param name="inputSeries">Input series.</param>
|
||
/// <param name="outputSeries">Output series.</param>
|
||
public void Filter(DateRangeType dateRange,
|
||
string rangeElements,
|
||
Series inputSeries,
|
||
Series outputSeries)
|
||
{
|
||
// Check arguments
|
||
if (rangeElements == null)
|
||
throw new ArgumentNullException("rangeElements");
|
||
if (inputSeries == null)
|
||
throw new ArgumentNullException("inputSeries");
|
||
|
||
// Filter points using filtering interface
|
||
Filter(new PointElementFilter(this, dateRange, rangeElements),
|
||
ConvertToSeriesArray(inputSeries, false),
|
||
ConvertToSeriesArray(outputSeries, false));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Filters a series' data points, either removing the specified points
|
||
/// or marking them as empty for the given date/time ranges.
|
||
/// The filtered Series objects are used to store the modified data.
|
||
/// </summary>
|
||
/// <param name="dateRange">Element type.</param>
|
||
/// <param name="rangeElements">Specifies the elements within the date/time range
|
||
/// (specified by the dateRange parameter) that will be filtered. Can be a single value (e.g. "7"),
|
||
/// comma-separated values (e.g. "5,6"), a range of values (e.g. 9-11),
|
||
/// or any variation thereof (e.g. "5,6,9-11").</param>
|
||
/// <param name="inputSeriesNames">Comma separated list of input series names.</param>
|
||
public void Filter(DateRangeType dateRange,
|
||
string rangeElements,
|
||
string inputSeriesNames)
|
||
{
|
||
// Check arguments
|
||
if (rangeElements == null)
|
||
throw new ArgumentNullException("rangeElements");
|
||
if (inputSeriesNames == null)
|
||
throw new ArgumentNullException("inputSeriesNames");
|
||
|
||
Filter(dateRange,
|
||
rangeElements,
|
||
inputSeriesNames,
|
||
"");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Filters a series' data points by applying a filtering rule to the first Y-value of data points.
|
||
/// The Series object that is filtered is used to store the modified data.
|
||
/// </summary>
|
||
/// <param name="compareMethod">Value comparing method.</param>
|
||
/// <param name="compareValue">Value to compare with.</param>
|
||
/// <param name="inputSeries">Input series.</param>
|
||
public void Filter(CompareMethod compareMethod,
|
||
double compareValue,
|
||
Series inputSeries)
|
||
{
|
||
// Check arguments
|
||
if (inputSeries == null)
|
||
throw new ArgumentNullException("inputSeries");
|
||
|
||
Filter(compareMethod,
|
||
compareValue,
|
||
inputSeries,
|
||
null,
|
||
"Y");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Filters a series' data points by applying a filtering rule to the first Y-value of data points.
|
||
/// </summary>
|
||
/// <param name="compareMethod">Value comparing method.</param>
|
||
/// <param name="compareValue">Value to compare with.</param>
|
||
/// <param name="inputSeries">Input series.</param>
|
||
/// <param name="outputSeries">Output series.</param>
|
||
public void Filter(CompareMethod compareMethod,
|
||
double compareValue,
|
||
Series inputSeries,
|
||
Series outputSeries)
|
||
{
|
||
// Check arguments
|
||
if (inputSeries == null)
|
||
throw new ArgumentNullException("inputSeries");
|
||
|
||
// Filter points using filtering interface
|
||
Filter(new PointValueFilter(compareMethod, compareValue, "Y"),
|
||
ConvertToSeriesArray(inputSeries, false),
|
||
ConvertToSeriesArray(outputSeries, false));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Filters a series' data points by applying a filtering rule to the specified value for comparison.
|
||
/// </summary>
|
||
/// <param name="compareMethod">Value comparing method.</param>
|
||
/// <param name="compareValue">Value to compare with.</param>
|
||
/// <param name="inputSeries">Input series.</param>
|
||
/// <param name="outputSeries">Output series.</param>
|
||
/// <param name="usingValue">The data point value that the filtering rule is applied to. Can be X, Y, Y2, Y3, etc.</param>
|
||
public void Filter(CompareMethod compareMethod,
|
||
double compareValue,
|
||
Series inputSeries,
|
||
Series outputSeries,
|
||
string usingValue)
|
||
{
|
||
// Check arguments
|
||
if (inputSeries == null)
|
||
throw new ArgumentNullException("inputSeries");
|
||
if (usingValue == null)
|
||
throw new ArgumentNullException("usingValue");
|
||
|
||
// Filter points using filtering interface
|
||
Filter(new PointValueFilter(compareMethod, compareValue, usingValue),
|
||
ConvertToSeriesArray(inputSeries, false),
|
||
ConvertToSeriesArray(outputSeries, false));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Filters one or more series by applying a filtering rule to the first Y-value of the first series' data points.
|
||
/// The filtered Series objects are used to store the modified data.
|
||
/// </summary>
|
||
/// <param name="compareMethod">Value comparing method.</param>
|
||
/// <param name="compareValue">Value to compare with.</param>
|
||
/// <param name="inputSeriesNames">Comma separated list of input series names.</param>
|
||
public void Filter(CompareMethod compareMethod,
|
||
double compareValue,
|
||
string inputSeriesNames)
|
||
{
|
||
// Check arguments
|
||
if (inputSeriesNames == null)
|
||
throw new ArgumentNullException("inputSeriesNames");
|
||
|
||
Filter(compareMethod,
|
||
compareValue,
|
||
inputSeriesNames,
|
||
"",
|
||
"Y");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Filters one or more series by applying a filtering rule to the first Y-value of the first series' data points.
|
||
/// </summary>
|
||
/// <param name="compareMethod">Value comparing method.</param>
|
||
/// <param name="compareValue">Value to compare with.</param>
|
||
/// <param name="inputSeriesNames">Comma separated list of input series names.</param>
|
||
/// <param name="outputSeriesNames">Comma separated list of output series names.</param>
|
||
public void Filter(CompareMethod compareMethod,
|
||
double compareValue,
|
||
string inputSeriesNames,
|
||
string outputSeriesNames)
|
||
{
|
||
// Check arguments
|
||
if (inputSeriesNames == null)
|
||
throw new ArgumentNullException("inputSeriesNames");
|
||
|
||
// Filter points using filtering interface
|
||
Filter(new PointValueFilter(compareMethod, compareValue, "Y"),
|
||
ConvertToSeriesArray(inputSeriesNames, false),
|
||
ConvertToSeriesArray(outputSeriesNames, true));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Filters one or more series by applying a filtering rule to the specified value of the first series' data points.
|
||
/// </summary>
|
||
/// <param name="compareMethod">Value comparing method.</param>
|
||
/// <param name="compareValue">Value to compare with.</param>
|
||
/// <param name="inputSeriesNames">Comma separated input series names.</param>
|
||
/// <param name="outputSeriesNames">Comma separated output series names.</param>
|
||
/// <param name="usingValue">The data point value that the filtering rule is applied to. Can be X, Y, Y2, Y3, etc.</param>
|
||
public void Filter(CompareMethod compareMethod,
|
||
double compareValue,
|
||
string inputSeriesNames,
|
||
string outputSeriesNames,
|
||
string usingValue)
|
||
{
|
||
// Check arguments
|
||
if (inputSeriesNames == null)
|
||
throw new ArgumentNullException("inputSeriesNames");
|
||
if (usingValue == null)
|
||
throw new ArgumentNullException("usingValue");
|
||
|
||
// Filter points using filtering interface
|
||
Filter(new PointValueFilter(compareMethod, compareValue, usingValue),
|
||
ConvertToSeriesArray(inputSeriesNames, false),
|
||
ConvertToSeriesArray(outputSeriesNames, true));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Filters all data points in one or more series except for a specified number of points.
|
||
/// The points that are not filtered correspond to points in the first input series that have the largest or smallest values.
|
||
/// </summary>
|
||
/// <param name="pointCount">The number of data points that the filtering operation will not remove.</param>
|
||
/// <param name="inputSeriesNames">Comma separated list of input series names.</param>
|
||
/// <param name="outputSeriesNames">Comma separated list of output series names.</param>
|
||
/// <param name="usingValue">The data point value that the filtering rule is applied to. Can be X, Y, Y2, Y3, etc.</param>
|
||
/// <param name="getTopValues">The largest values are kept if set to true; otherwise the smallest values are kept.</param>
|
||
public void FilterTopN(int pointCount,
|
||
string inputSeriesNames,
|
||
string outputSeriesNames,
|
||
string usingValue,
|
||
bool getTopValues)
|
||
{
|
||
// Check arguments
|
||
if (inputSeriesNames == null)
|
||
throw new ArgumentNullException("inputSeriesNames");
|
||
if (usingValue == null)
|
||
throw new ArgumentNullException("usingValue");
|
||
|
||
FilterTopN(pointCount,
|
||
ConvertToSeriesArray(inputSeriesNames, false),
|
||
ConvertToSeriesArray(outputSeriesNames, true),
|
||
usingValue,
|
||
getTopValues);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Filters out all data points in a series except for a specified number of points with the largest (first) Y-values.
|
||
/// The Series object that is filtered is used to store the modified data.
|
||
/// </summary>
|
||
/// <param name="pointCount">The number of data points that the filtering operation will not remove.</param>
|
||
/// <param name="inputSeries">Input series.</param>
|
||
public void FilterTopN(int pointCount,
|
||
Series inputSeries)
|
||
{
|
||
// Check arguments
|
||
if (inputSeries == null)
|
||
throw new ArgumentNullException("inputSeries");
|
||
|
||
FilterTopN(pointCount,
|
||
ConvertToSeriesArray(inputSeries, false),
|
||
null,
|
||
"Y",
|
||
true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Filters all data points in a series except for a specified number of points with the largest first Y-values.
|
||
/// </summary>
|
||
/// <param name="pointCount">The number of data points that the filtering operation will not remove.</param>
|
||
/// <param name="inputSeries">Input series.</param>
|
||
/// <param name="outputSeries">Output series.</param>
|
||
public void FilterTopN(int pointCount,
|
||
Series inputSeries,
|
||
Series outputSeries)
|
||
{
|
||
// Check arguments
|
||
if (inputSeries == null)
|
||
throw new ArgumentNullException("inputSeries");
|
||
|
||
FilterTopN(pointCount,
|
||
ConvertToSeriesArray(inputSeries, false),
|
||
ConvertToSeriesArray(outputSeries, false),
|
||
"Y",
|
||
true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Filters all data points in a series except for a specified number of points with the largest values.
|
||
/// </summary>
|
||
/// <param name="pointCount">The number of data points that the filtering operation will not remove.</param>
|
||
/// <param name="inputSeries">Input series.</param>
|
||
/// <param name="outputSeries">Output series.</param>
|
||
/// <param name="usingValue">The data point value that the filtering rule is applied to. Can be X, Y, Y2, Y3, etc.</param>
|
||
public void FilterTopN(int pointCount,
|
||
Series inputSeries,
|
||
Series outputSeries,
|
||
string usingValue)
|
||
{
|
||
// Check arguments
|
||
if (inputSeries == null)
|
||
throw new ArgumentNullException("inputSeries");
|
||
if (usingValue == null)
|
||
throw new ArgumentNullException("usingValue");
|
||
|
||
FilterTopN(pointCount,
|
||
ConvertToSeriesArray(inputSeries, false),
|
||
ConvertToSeriesArray(outputSeries, false),
|
||
usingValue,
|
||
true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Filters all data points in a series except for a specified number of points with the smallest or largest values.
|
||
/// </summary>
|
||
/// <param name="pointCount">The number of data points that the filtering operation will not remove.</param>
|
||
/// <param name="inputSeries">Input series.</param>
|
||
/// <param name="outputSeries">Output series.</param>
|
||
/// <param name="usingValue">The data point value that the filtering rule is applied to. Can be X, Y, Y2, Y3, etc.</param>
|
||
/// <param name="getTopValues">The largest values are kept if set to true; otherwise the smallest values are kept.</param>
|
||
public void FilterTopN(int pointCount,
|
||
Series inputSeries,
|
||
Series outputSeries,
|
||
string usingValue,
|
||
bool getTopValues)
|
||
{
|
||
// Check arguments
|
||
if (inputSeries == null)
|
||
throw new ArgumentNullException("inputSeries");
|
||
if (usingValue == null)
|
||
throw new ArgumentNullException("usingValue");
|
||
|
||
FilterTopN(pointCount,
|
||
ConvertToSeriesArray(inputSeries, false),
|
||
ConvertToSeriesArray(outputSeries, false),
|
||
usingValue,
|
||
getTopValues);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Filters all data points in one or more series except for a specified number of points.
|
||
/// The points that are not filtered correspond to points in the first series that have the largest first Y-values.
|
||
/// The Series objects that are filtered are used to store the modified data.
|
||
/// </summary>
|
||
/// <param name="pointCount">The number of data points that the filtering operation will not remove.</param>
|
||
/// <param name="inputSeriesNames">Comma separated list of input series names.</param>
|
||
public void FilterTopN(int pointCount,
|
||
string inputSeriesNames)
|
||
{
|
||
// Check arguments
|
||
if (inputSeriesNames == null)
|
||
throw new ArgumentNullException("inputSeriesNames");
|
||
|
||
FilterTopN(pointCount,
|
||
ConvertToSeriesArray(inputSeriesNames, false),
|
||
null,
|
||
"Y",
|
||
true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Filters out data points in one or more series except for a specified number of points.
|
||
/// The points that aren't filtered correspond to points in the first series that have the largest first Y-values.
|
||
/// </summary>
|
||
/// <param name="pointCount">The number of data points that the filtering operation will not remove.</param>
|
||
/// <param name="inputSeriesNames">Comma separated list of input series names.</param>
|
||
/// <param name="outputSeriesNames">Comma separated list of output series names.</param>
|
||
public void FilterTopN(int pointCount,
|
||
string inputSeriesNames,
|
||
string outputSeriesNames)
|
||
{
|
||
// Check arguments
|
||
if (inputSeriesNames == null)
|
||
throw new ArgumentNullException("inputSeriesNames");
|
||
|
||
FilterTopN(pointCount,
|
||
ConvertToSeriesArray(inputSeriesNames, false),
|
||
ConvertToSeriesArray(outputSeriesNames, true),
|
||
"Y",
|
||
true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Filters all data points in one or more series except for a specified number of points.
|
||
/// The points that are not filtered correspond to points in the first series that have the largest values.
|
||
/// </summary>
|
||
/// <param name="pointCount">The number of data points that the filtering operation will not remove.</param>
|
||
/// <param name="inputSeriesNames">Comma separated list of input series names.</param>
|
||
/// <param name="outputSeriesNames">Comma separated list of output series names.</param>
|
||
/// <param name="usingValue">The data point value that the filtering rule is applied to. Can be X, Y, Y2, Y3, etc.</param>
|
||
public void FilterTopN(int pointCount,
|
||
string inputSeriesNames,
|
||
string outputSeriesNames,
|
||
string usingValue)
|
||
{
|
||
// Check arguments
|
||
if (inputSeriesNames == null)
|
||
throw new ArgumentNullException("inputSeriesNames");
|
||
if (usingValue == null)
|
||
throw new ArgumentNullException("usingValue");
|
||
|
||
FilterTopN(pointCount,
|
||
ConvertToSeriesArray(inputSeriesNames, false),
|
||
ConvertToSeriesArray(outputSeriesNames, true),
|
||
usingValue,
|
||
true);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Performs custom filtering on a series' data points.
|
||
/// The Series object that is filtered is used to store the modified data.
|
||
/// </summary>
|
||
/// <param name="filterInterface">Filtering interface.</param>
|
||
/// <param name="inputSeries">Input series.</param>
|
||
public void Filter(IDataPointFilter filterInterface,
|
||
Series inputSeries)
|
||
{
|
||
// Check arguments
|
||
if (filterInterface == null)
|
||
throw new ArgumentNullException("filterInterface");
|
||
if (inputSeries == null)
|
||
throw new ArgumentNullException("inputSeries");
|
||
|
||
Filter(filterInterface,
|
||
ConvertToSeriesArray(inputSeries, false),
|
||
null);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Performs custom filtering on a series' data points.
|
||
/// </summary>
|
||
/// <param name="filterInterface">Filtering interface.</param>
|
||
/// <param name="inputSeries">Input series.</param>
|
||
/// <param name="outputSeries">Output series.</param>
|
||
public void Filter(IDataPointFilter filterInterface,
|
||
Series inputSeries,
|
||
Series outputSeries)
|
||
{
|
||
// Check arguments
|
||
if (filterInterface == null)
|
||
throw new ArgumentNullException("filterInterface");
|
||
if (inputSeries == null)
|
||
throw new ArgumentNullException("inputSeries");
|
||
|
||
Filter(filterInterface,
|
||
ConvertToSeriesArray(inputSeries, false),
|
||
ConvertToSeriesArray(outputSeries, false));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Performs custom filtering on one or more series' data points, based on the first series' points.
|
||
/// The filtered series are also used to store the modified data.
|
||
/// </summary>
|
||
/// <param name="filterInterface">Filtering interface.</param>
|
||
/// <param name="inputSeriesNames">Comma separated list of input series names.</param>
|
||
public void Filter(IDataPointFilter filterInterface,
|
||
string inputSeriesNames)
|
||
{
|
||
// Check arguments
|
||
if (filterInterface == null)
|
||
throw new ArgumentNullException("filterInterface");
|
||
if (inputSeriesNames == null)
|
||
throw new ArgumentNullException("inputSeriesNames");
|
||
|
||
Filter(filterInterface,
|
||
ConvertToSeriesArray(inputSeriesNames, false),
|
||
null);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Performs custom filtering on one or more series' data points, based on the first series' points.
|
||
/// </summary>
|
||
/// <param name="filterInterface">Filtering interface.</param>
|
||
/// <param name="inputSeriesNames">Comma separated list of input series names.</param>
|
||
/// <param name="outputSeriesNames">Comma separated list of output series names.</param>
|
||
public void Filter(IDataPointFilter filterInterface,
|
||
string inputSeriesNames,
|
||
string outputSeriesNames)
|
||
{
|
||
// Check arguments
|
||
if (filterInterface == null)
|
||
throw new ArgumentNullException("filterInterface");
|
||
if (inputSeriesNames == null)
|
||
throw new ArgumentNullException("inputSeriesNames");
|
||
|
||
Filter(filterInterface,
|
||
ConvertToSeriesArray(inputSeriesNames, false),
|
||
ConvertToSeriesArray(outputSeriesNames, true));
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Grouping methods
|
||
|
||
/// <summary>
|
||
/// Class stores information about the grouping function type and
|
||
/// index of output value.
|
||
/// </summary>
|
||
private class GroupingFunctionInfo
|
||
{
|
||
// AxisName of the grouping function
|
||
internal GroupingFunction function = GroupingFunction.None;
|
||
|
||
// Index of the Y value for storing results
|
||
internal int outputIndex = 0;
|
||
|
||
/// <summary>
|
||
/// Constructor.
|
||
/// </summary>
|
||
internal GroupingFunctionInfo()
|
||
{
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Grouping by X value, when it’s a string (stored in AxisLabel property).
|
||
/// </summary>
|
||
/// <param name="formula">Grouping formula.</param>
|
||
/// <param name="inputSeries">Array of input series.</param>
|
||
/// <param name="outputSeries">Array of output series.</param>
|
||
private void GroupByAxisLabel(string formula, Series[] inputSeries, Series[] outputSeries)
|
||
{
|
||
// Check arguments
|
||
if (formula == null)
|
||
throw new ArgumentNullException("formula");
|
||
|
||
//**************************************************
|
||
//** Check input/output series arrays
|
||
//**************************************************
|
||
CheckSeriesArrays(inputSeries, outputSeries);
|
||
|
||
//**************************************************
|
||
//** Check and parse formula
|
||
//**************************************************
|
||
int outputValuesNumber = 1;
|
||
GroupingFunctionInfo[] functions = GetGroupingFunctions(inputSeries, formula, out outputValuesNumber);
|
||
|
||
//**************************************************
|
||
//** Loop through all input series
|
||
//**************************************************
|
||
for(int seriesIndex = 0; seriesIndex < inputSeries.Length; seriesIndex++)
|
||
{
|
||
// Define an input and output series
|
||
Series input = inputSeries[seriesIndex];
|
||
Series output = input;
|
||
if(outputSeries != null && seriesIndex < outputSeries.Length)
|
||
{
|
||
output = outputSeries[seriesIndex];
|
||
|
||
// Remove all points from the output series
|
||
if(output.Name != input.Name)
|
||
{
|
||
output.Points.Clear();
|
||
|
||
// Copy X values type
|
||
if(output.XValueType == ChartValueType.Auto || output.autoXValueType)
|
||
{
|
||
output.XValueType = input.XValueType;
|
||
output.autoXValueType = true;
|
||
}
|
||
// Copy Y values type
|
||
if(output.YValueType == ChartValueType.Auto || output.autoYValueType)
|
||
{
|
||
output.YValueType = input.YValueType;
|
||
output.autoYValueType = true;
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
// Copy input data into temp storage
|
||
if(input != output)
|
||
{
|
||
Series inputTemp = new Series("Temp", input.YValuesPerPoint);
|
||
foreach(DataPoint point in input.Points)
|
||
{
|
||
DataPoint dp = new DataPoint(inputTemp);
|
||
dp.AxisLabel = point.AxisLabel;
|
||
dp.XValue = point.XValue;
|
||
point.YValues.CopyTo(dp.YValues, 0);
|
||
dp.IsEmpty = point.IsEmpty;
|
||
inputTemp.Points.Add(dp);
|
||
}
|
||
input = inputTemp;
|
||
}
|
||
|
||
// No points to group
|
||
if(input.Points.Count == 0)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// Make sure there is enough Y values per point
|
||
output.YValuesPerPoint = outputValuesNumber - 1;
|
||
|
||
//**************************************************
|
||
//** Sort input data by axis label
|
||
//**************************************************
|
||
input.Sort(PointSortOrder.Ascending, "AxisLabel");
|
||
|
||
//**************************************************
|
||
//** Initialize interval & value tracking variables
|
||
//**************************************************
|
||
int intervalFirstIndex = 0;
|
||
int intervalLastIndex = 0;
|
||
|
||
//**************************************************
|
||
//** Allocate array for storing temp.
|
||
//** values of the point
|
||
//**************************************************
|
||
double[] pointTempValues = new double[outputValuesNumber];
|
||
|
||
//**************************************************
|
||
//** Loop through the series points
|
||
//**************************************************
|
||
string currentLabel = null;
|
||
bool lastPoint = false;
|
||
int emptyPointsSkipped = 0;
|
||
for(int pointIndex = 0; pointIndex <= input.Points.Count && !lastPoint; pointIndex++)
|
||
{
|
||
bool endOfInterval = false;
|
||
|
||
//**************************************************
|
||
//** Check if it's the last point
|
||
//**************************************************
|
||
if(pointIndex == input.Points.Count)
|
||
{
|
||
// End of the group interval detected
|
||
lastPoint = true;
|
||
intervalLastIndex = pointIndex - 1;
|
||
pointIndex = intervalLastIndex;
|
||
endOfInterval = true;
|
||
}
|
||
|
||
// Set current axis label
|
||
if(!endOfInterval && currentLabel == null)
|
||
{
|
||
currentLabel = input.Points[pointIndex].AxisLabel;
|
||
}
|
||
|
||
//**************************************************
|
||
//** Check if current point X value is inside current group
|
||
//**************************************************
|
||
if(!endOfInterval && input.Points[pointIndex].AxisLabel != currentLabel)
|
||
{
|
||
// End of the group interval detected
|
||
intervalLastIndex = pointIndex - 1;
|
||
endOfInterval = true;
|
||
}
|
||
|
||
//**************************************************
|
||
//** Process data at end of the interval
|
||
//**************************************************
|
||
if(endOfInterval)
|
||
{
|
||
// Finalize the calculation
|
||
ProcessPointValues(
|
||
functions,
|
||
pointTempValues,
|
||
inputSeries[seriesIndex],
|
||
input.Points[pointIndex],
|
||
pointIndex,
|
||
intervalFirstIndex,
|
||
intervalLastIndex,
|
||
true,
|
||
ref emptyPointsSkipped);
|
||
|
||
//**************************************************
|
||
//** Calculate the X values
|
||
//**************************************************
|
||
if(functions[0].function == GroupingFunction.Center)
|
||
{
|
||
pointTempValues[0] =
|
||
(inputSeries[seriesIndex].Points[intervalFirstIndex].XValue +
|
||
inputSeries[seriesIndex].Points[intervalLastIndex].XValue) / 2.0;
|
||
}
|
||
else if(functions[0].function == GroupingFunction.First)
|
||
{
|
||
pointTempValues[0] =
|
||
inputSeries[seriesIndex].Points[intervalFirstIndex].XValue;
|
||
}
|
||
if(functions[0].function == GroupingFunction.Last)
|
||
{
|
||
pointTempValues[0] =
|
||
inputSeries[seriesIndex].Points[intervalLastIndex].XValue;
|
||
}
|
||
|
||
//**************************************************
|
||
//** Create new point object
|
||
//**************************************************
|
||
DataPoint newPoint = new DataPoint();
|
||
newPoint.ResizeYValueArray(outputValuesNumber - 1);
|
||
newPoint.XValue = pointTempValues[0];
|
||
newPoint.AxisLabel = currentLabel;
|
||
for(int i = 1; i < pointTempValues.Length; i++)
|
||
{
|
||
newPoint.YValues[i - 1] = pointTempValues[i];
|
||
}
|
||
|
||
//**************************************************
|
||
//** Remove grouped points if output and input
|
||
//** series are the same
|
||
//**************************************************
|
||
int newPointIndex = output.Points.Count;
|
||
if(output == input)
|
||
{
|
||
newPointIndex = intervalFirstIndex;
|
||
pointIndex = newPointIndex + 1;
|
||
|
||
// Remove grouped points
|
||
for(int removedPoint = intervalFirstIndex; removedPoint <= intervalLastIndex; removedPoint++)
|
||
{
|
||
output.Points.RemoveAt(intervalFirstIndex);
|
||
}
|
||
}
|
||
|
||
//**************************************************
|
||
//** Add point to the output series
|
||
//**************************************************
|
||
output.Points.Insert(newPointIndex, newPoint);
|
||
|
||
|
||
// Set new group interval indexes
|
||
intervalFirstIndex = pointIndex;
|
||
intervalLastIndex = pointIndex;
|
||
|
||
// Reset number of skipped points
|
||
emptyPointsSkipped = 0;
|
||
currentLabel = null;
|
||
|
||
// Process point once again
|
||
--pointIndex;
|
||
|
||
continue;
|
||
}
|
||
|
||
//**************************************************
|
||
//** Use current point values in the formula
|
||
//**************************************************
|
||
ProcessPointValues(
|
||
functions,
|
||
pointTempValues,
|
||
inputSeries[seriesIndex],
|
||
input.Points[pointIndex],
|
||
pointIndex,
|
||
intervalFirstIndex,
|
||
intervalLastIndex,
|
||
false,
|
||
ref emptyPointsSkipped);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Groups series points in the interval with offset
|
||
/// </summary>
|
||
/// <param name="formula">Grouping formula.</param>
|
||
/// <param name="interval">Interval size.</param>
|
||
/// <param name="intervalType">Interval type.</param>
|
||
/// <param name="intervalOffset">Interval offset size.</param>
|
||
/// <param name="intervalOffsetType">Interval offset type.</param>
|
||
/// <param name="inputSeries">Array of input series.</param>
|
||
/// <param name="outputSeries">Array of output series.</param>
|
||
private void Group(string formula,
|
||
double interval,
|
||
IntervalType intervalType,
|
||
double intervalOffset,
|
||
IntervalType intervalOffsetType,
|
||
Series[] inputSeries,
|
||
Series[] outputSeries)
|
||
{
|
||
// Check arguments
|
||
if (formula == null)
|
||
throw new ArgumentNullException("formula");
|
||
|
||
//**************************************************
|
||
//** Check input/output series arrays
|
||
//**************************************************
|
||
CheckSeriesArrays(inputSeries, outputSeries);
|
||
|
||
//**************************************************
|
||
//** Check and parse formula
|
||
//**************************************************
|
||
int outputValuesNumber = 1;
|
||
GroupingFunctionInfo[] functions = GetGroupingFunctions(inputSeries, formula, out outputValuesNumber);
|
||
|
||
//**************************************************
|
||
//** Loop through all input series
|
||
//**************************************************
|
||
for(int seriesIndex = 0; seriesIndex < inputSeries.Length; seriesIndex++)
|
||
{
|
||
// Define an input and output series
|
||
Series input = inputSeries[seriesIndex];
|
||
Series output = input;
|
||
if(outputSeries != null && seriesIndex < outputSeries.Length)
|
||
{
|
||
output = outputSeries[seriesIndex];
|
||
|
||
// Remove all points from the output series
|
||
if(output.Name != input.Name)
|
||
{
|
||
output.Points.Clear();
|
||
|
||
// Copy X values type
|
||
if(output.XValueType == ChartValueType.Auto || output.autoXValueType)
|
||
{
|
||
output.XValueType = input.XValueType;
|
||
output.autoXValueType = true;
|
||
}
|
||
// Copy Y values type
|
||
if(output.YValueType == ChartValueType.Auto || output.autoYValueType)
|
||
{
|
||
output.YValueType = input.YValueType;
|
||
output.autoYValueType = true;
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
// No points to group
|
||
if(input.Points.Count == 0)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// Make sure there is enough Y values per point
|
||
output.YValuesPerPoint = outputValuesNumber - 1;
|
||
|
||
//**************************************************
|
||
//** Initialize interval & value tracking variables
|
||
//**************************************************
|
||
int intervalFirstIndex = 0;
|
||
int intervalLastIndex = 0;
|
||
double intervalFrom = 0;
|
||
double intervalTo = 0;
|
||
|
||
// Set interval start point
|
||
intervalFrom = input.Points[0].XValue;
|
||
|
||
// Adjust start point depending on the interval type
|
||
intervalFrom = ChartHelper.AlignIntervalStart(intervalFrom, interval, ConvertIntervalType(intervalType));
|
||
|
||
// Add offset to the start position
|
||
double offsetFrom = 0;
|
||
if( intervalOffset != 0 )
|
||
{
|
||
offsetFrom = intervalFrom + ChartHelper.GetIntervalSize(intervalFrom,
|
||
intervalOffset,
|
||
ConvertIntervalType(intervalOffsetType));
|
||
|
||
// Check if there are points left outside first group
|
||
if(input.Points[0].XValue < offsetFrom)
|
||
{
|
||
if(intervalType == IntervalType.Number)
|
||
{
|
||
intervalFrom = offsetFrom + ChartHelper.GetIntervalSize(offsetFrom,
|
||
-interval,
|
||
ConvertIntervalType(intervalType));
|
||
}
|
||
else
|
||
{
|
||
intervalFrom = offsetFrom - ChartHelper.GetIntervalSize(offsetFrom,
|
||
interval,
|
||
ConvertIntervalType(intervalType));
|
||
}
|
||
intervalTo = offsetFrom;
|
||
|
||
}
|
||
else
|
||
{
|
||
intervalFrom = offsetFrom;
|
||
intervalTo = intervalFrom + ChartHelper.GetIntervalSize(intervalFrom, interval, ConvertIntervalType(intervalType));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
intervalTo = intervalFrom + ChartHelper.GetIntervalSize(intervalFrom, interval, ConvertIntervalType(intervalType));
|
||
}
|
||
|
||
//**************************************************
|
||
//** Allocate array for storing temp.
|
||
//** values of the point
|
||
//**************************************************
|
||
double[] pointTempValues = new double[outputValuesNumber];
|
||
|
||
|
||
//**************************************************
|
||
//** Loop through the series points
|
||
//**************************************************
|
||
bool lastPoint = false;
|
||
int emptyPointsSkipped = 0;
|
||
int pointsNumberInInterval = 0;
|
||
for(int pointIndex = 0; pointIndex <= input.Points.Count && !lastPoint; pointIndex++)
|
||
{
|
||
bool endOfInterval = false;
|
||
|
||
//**************************************************
|
||
//** Check if series is sorted by X value
|
||
//**************************************************
|
||
if(pointIndex > 0 && pointIndex < input.Points.Count)
|
||
{
|
||
if(input.Points[pointIndex].XValue < input.Points[pointIndex - 1].XValue)
|
||
{
|
||
throw (new InvalidOperationException(SR.ExceptionDataManipulatorGroupedSeriesNotSorted));
|
||
}
|
||
}
|
||
|
||
//**************************************************
|
||
//** Check if it's the last point
|
||
//**************************************************
|
||
if(pointIndex == input.Points.Count)
|
||
{
|
||
// End of the group interval detected
|
||
lastPoint = true;
|
||
intervalLastIndex = pointIndex - 1;
|
||
pointIndex = intervalLastIndex;
|
||
endOfInterval = true;
|
||
}
|
||
|
||
//**************************************************
|
||
//** Check if current point X value is inside current group
|
||
//**************************************************
|
||
if(!endOfInterval && input.Points[pointIndex].XValue >= intervalTo)
|
||
{
|
||
// End of the group interval detected
|
||
if(pointIndex == 0)
|
||
{
|
||
continue;
|
||
}
|
||
intervalLastIndex = pointIndex - 1;
|
||
endOfInterval = true;
|
||
}
|
||
|
||
//**************************************************
|
||
//** Process data at end of the interval
|
||
//**************************************************
|
||
if(endOfInterval)
|
||
{
|
||
// Add grouped point only if there are non empty points in the interval
|
||
if(pointsNumberInInterval > emptyPointsSkipped)
|
||
{
|
||
// Finalize the calculation
|
||
ProcessPointValues(
|
||
functions,
|
||
pointTempValues,
|
||
inputSeries[seriesIndex],
|
||
input.Points[pointIndex],
|
||
pointIndex,
|
||
intervalFirstIndex,
|
||
intervalLastIndex,
|
||
true,
|
||
ref emptyPointsSkipped);
|
||
|
||
//**************************************************
|
||
//** Calculate the X values
|
||
//**************************************************
|
||
if(functions[0].function == GroupingFunction.Center)
|
||
{
|
||
pointTempValues[0] = (intervalFrom + intervalTo) / 2.0;
|
||
}
|
||
else if(functions[0].function == GroupingFunction.First)
|
||
{
|
||
pointTempValues[0] = intervalFrom;
|
||
}
|
||
if(functions[0].function == GroupingFunction.Last)
|
||
{
|
||
pointTempValues[0] = intervalTo;
|
||
}
|
||
|
||
//**************************************************
|
||
//** Create new point object
|
||
//**************************************************
|
||
DataPoint newPoint = new DataPoint();
|
||
newPoint.ResizeYValueArray(outputValuesNumber - 1);
|
||
newPoint.XValue = pointTempValues[0];
|
||
for(int i = 1; i < pointTempValues.Length; i++)
|
||
{
|
||
newPoint.YValues[i - 1] = pointTempValues[i];
|
||
}
|
||
|
||
//**************************************************
|
||
//** Remove grouped points if output and input
|
||
//** series are the same
|
||
//**************************************************
|
||
int newPointIndex = output.Points.Count;
|
||
if(output == input)
|
||
{
|
||
newPointIndex = intervalFirstIndex;
|
||
pointIndex = newPointIndex + 1;
|
||
|
||
// Remove grouped points
|
||
for(int removedPoint = intervalFirstIndex; removedPoint <= intervalLastIndex; removedPoint++)
|
||
{
|
||
output.Points.RemoveAt(intervalFirstIndex);
|
||
}
|
||
}
|
||
|
||
//**************************************************
|
||
//** Add point to the output series
|
||
//**************************************************
|
||
output.Points.Insert(newPointIndex, newPoint);
|
||
}
|
||
|
||
// Set new From To values of the group interval
|
||
intervalFrom = intervalTo;
|
||
intervalTo = intervalFrom + ChartHelper.GetIntervalSize(intervalFrom, interval, ConvertIntervalType(intervalType));
|
||
|
||
// Set new group interval indexes
|
||
intervalFirstIndex = pointIndex;
|
||
intervalLastIndex = pointIndex;
|
||
|
||
// Reset number of points in the interval
|
||
pointsNumberInInterval = 0;
|
||
|
||
// Reset number of skipped points
|
||
emptyPointsSkipped = 0;
|
||
|
||
// Process point once again
|
||
--pointIndex;
|
||
|
||
continue;
|
||
}
|
||
|
||
//**************************************************
|
||
//** Use current point values in the formula
|
||
//**************************************************
|
||
ProcessPointValues(
|
||
functions,
|
||
pointTempValues,
|
||
inputSeries[seriesIndex],
|
||
input.Points[pointIndex],
|
||
pointIndex,
|
||
intervalFirstIndex,
|
||
intervalLastIndex,
|
||
false,
|
||
ref emptyPointsSkipped);
|
||
|
||
// Increase number of points in the group
|
||
++pointsNumberInInterval;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Adds current point values to the temp. formula results.
|
||
/// </summary>
|
||
/// <param name="functions">Array of functions type.</param>
|
||
/// <param name="pointTempValues">Temp. point values.</param>
|
||
/// <param name="series">Point series.</param>
|
||
/// <param name="point">Current point.</param>
|
||
/// <param name="pointIndex">Current point index.</param>
|
||
/// <param name="intervalFirstIndex">Index of the first point in the interval.</param>
|
||
/// <param name="intervalLastIndex">Index of the last point in the interval.</param>
|
||
/// <param name="finalPass">Indicates that interval processing is finished.</param>
|
||
/// <param name="numberOfEmptyPoints">Number of skipped points in the interval.</param>
|
||
private void ProcessPointValues(
|
||
GroupingFunctionInfo[] functions,
|
||
double[] pointTempValues,
|
||
Series series,
|
||
DataPoint point,
|
||
int pointIndex,
|
||
int intervalFirstIndex,
|
||
int intervalLastIndex,
|
||
bool finalPass,
|
||
ref int numberOfEmptyPoints)
|
||
{
|
||
//*******************************************************************
|
||
//** Initialize temp data if it's the first point in the interval
|
||
//*******************************************************************
|
||
if(pointIndex == intervalFirstIndex && !finalPass)
|
||
{
|
||
// Initialize values depending on the function type
|
||
int funcIndex = 0;
|
||
foreach(GroupingFunctionInfo functionInfo in functions)
|
||
{
|
||
// Check that we do not exced number of input values
|
||
if(funcIndex > point.YValues.Length)
|
||
{
|
||
break;
|
||
}
|
||
|
||
// Initialize with zero
|
||
pointTempValues[functionInfo.outputIndex] = 0;
|
||
|
||
// Initialize with custom value depending on the formula
|
||
if(functionInfo.function == GroupingFunction.Min)
|
||
{
|
||
pointTempValues[functionInfo.outputIndex] = double.MaxValue;
|
||
}
|
||
|
||
else if(functionInfo.function == GroupingFunction.Max)
|
||
{
|
||
pointTempValues[functionInfo.outputIndex] = double.MinValue;
|
||
}
|
||
|
||
else if(functionInfo.function == GroupingFunction.First)
|
||
{
|
||
if(funcIndex == 0)
|
||
{
|
||
pointTempValues[0] = point.XValue;
|
||
}
|
||
else
|
||
{
|
||
pointTempValues[functionInfo.outputIndex] = point.YValues[funcIndex-1];
|
||
}
|
||
}
|
||
|
||
else if(functionInfo.function == GroupingFunction.HiLo ||
|
||
functionInfo.function == GroupingFunction.HiLoOpCl)
|
||
{
|
||
// Hi
|
||
pointTempValues[functionInfo.outputIndex] = double.MinValue;
|
||
//Lo
|
||
pointTempValues[functionInfo.outputIndex + 1] = double.MaxValue;
|
||
if(functionInfo.function == GroupingFunction.HiLoOpCl)
|
||
{
|
||
//Open
|
||
pointTempValues[functionInfo.outputIndex + 2] = point.YValues[funcIndex-1];
|
||
//Close
|
||
pointTempValues[functionInfo.outputIndex + 3] = 0;
|
||
}
|
||
}
|
||
|
||
// Increase current function index
|
||
++funcIndex;
|
||
}
|
||
}
|
||
|
||
//*******************************************************************
|
||
//** Add points values using formula
|
||
//*******************************************************************
|
||
if(!finalPass)
|
||
{
|
||
//*******************************************************************
|
||
//** Ignore empty points
|
||
//*******************************************************************
|
||
if(point.IsEmpty && this.IsEmptyPointIgnored)
|
||
{
|
||
++numberOfEmptyPoints;
|
||
return;
|
||
}
|
||
|
||
//*******************************************************************
|
||
//** Loop through each grouping function
|
||
//*******************************************************************
|
||
int funcIndex = 0;
|
||
foreach(GroupingFunctionInfo functionInfo in functions)
|
||
{
|
||
// Check that we do not exced number of input values
|
||
if(funcIndex > point.YValues.Length)
|
||
{
|
||
break;
|
||
}
|
||
|
||
// Process point values depending on the formula
|
||
if(functionInfo.function == GroupingFunction.Min &&
|
||
(!point.IsEmpty && this.IsEmptyPointIgnored))
|
||
{
|
||
pointTempValues[functionInfo.outputIndex] =
|
||
Math.Min(pointTempValues[functionInfo.outputIndex], point.YValues[funcIndex-1]);
|
||
}
|
||
|
||
else if(functionInfo.function == GroupingFunction.Max)
|
||
{
|
||
pointTempValues[functionInfo.outputIndex] =
|
||
Math.Max(pointTempValues[functionInfo.outputIndex], point.YValues[funcIndex-1]);
|
||
}
|
||
|
||
else if(functionInfo.function == GroupingFunction.Ave ||
|
||
functionInfo.function == GroupingFunction.Sum)
|
||
{
|
||
if(funcIndex == 0)
|
||
{
|
||
pointTempValues[0] += point.XValue;
|
||
}
|
||
else
|
||
{
|
||
pointTempValues[functionInfo.outputIndex] += point.YValues[funcIndex-1];
|
||
}
|
||
}
|
||
|
||
else if(functionInfo.function == GroupingFunction.Variance ||
|
||
functionInfo.function == GroupingFunction.Deviation)
|
||
{
|
||
pointTempValues[functionInfo.outputIndex] += point.YValues[funcIndex-1];
|
||
}
|
||
|
||
else if(functionInfo.function == GroupingFunction.Last)
|
||
{
|
||
if(funcIndex == 0)
|
||
{
|
||
pointTempValues[0] = point.XValue;
|
||
}
|
||
else
|
||
{
|
||
pointTempValues[functionInfo.outputIndex] = point.YValues[funcIndex-1];
|
||
}
|
||
}
|
||
|
||
else if(functionInfo.function == GroupingFunction.Count)
|
||
{
|
||
pointTempValues[functionInfo.outputIndex] += 1;
|
||
}
|
||
|
||
else if(functionInfo.function == GroupingFunction.HiLo ||
|
||
functionInfo.function == GroupingFunction.HiLoOpCl)
|
||
{
|
||
// Hi
|
||
pointTempValues[functionInfo.outputIndex] =
|
||
Math.Max(pointTempValues[functionInfo.outputIndex], point.YValues[funcIndex-1]);
|
||
// Lo
|
||
pointTempValues[functionInfo.outputIndex + 1] =
|
||
Math.Min(pointTempValues[functionInfo.outputIndex + 1], point.YValues[funcIndex-1]);
|
||
if(functionInfo.function == GroupingFunction.HiLoOpCl)
|
||
{
|
||
// Close
|
||
pointTempValues[functionInfo.outputIndex + 3] = point.YValues[funcIndex-1];
|
||
}
|
||
}
|
||
|
||
// Increase current function index
|
||
++funcIndex;
|
||
}
|
||
}
|
||
|
||
|
||
//*******************************************************************
|
||
//** Adjust formula results at final pass
|
||
//*******************************************************************
|
||
if(finalPass)
|
||
{
|
||
int funcIndex = 0;
|
||
foreach(GroupingFunctionInfo functionInfo in functions)
|
||
{
|
||
// Check that we do not exceed number of input values
|
||
if(funcIndex > point.YValues.Length)
|
||
{
|
||
break;
|
||
}
|
||
|
||
if(functionInfo.function == GroupingFunction.Ave)
|
||
{
|
||
pointTempValues[functionInfo.outputIndex] /= intervalLastIndex - intervalFirstIndex - numberOfEmptyPoints + 1;
|
||
}
|
||
|
||
if(functionInfo.function == GroupingFunction.DistinctCount)
|
||
{
|
||
// Initialize value with zero
|
||
pointTempValues[functionInfo.outputIndex] = 0;
|
||
|
||
// Create a list of uniques values
|
||
ArrayList uniqueValues = new ArrayList(intervalLastIndex - intervalFirstIndex + 1);
|
||
|
||
// Second pass through inteval points required for calculations
|
||
for(int secondPassIndex = intervalFirstIndex; secondPassIndex <= intervalLastIndex; secondPassIndex++)
|
||
{
|
||
// Ignore empty points
|
||
if(series.Points[secondPassIndex].IsEmpty && this.IsEmptyPointIgnored)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// Check if current value is in the unique list
|
||
if(!uniqueValues.Contains(series.Points[secondPassIndex].YValues[funcIndex-1]))
|
||
{
|
||
uniqueValues.Add(series.Points[secondPassIndex].YValues[funcIndex-1]);
|
||
}
|
||
}
|
||
|
||
// Get count of unique values
|
||
pointTempValues[functionInfo.outputIndex] = uniqueValues.Count;
|
||
}
|
||
|
||
else if(functionInfo.function == GroupingFunction.Variance ||
|
||
functionInfo.function == GroupingFunction.Deviation)
|
||
{
|
||
// Calculate average first
|
||
double average = pointTempValues[functionInfo.outputIndex] / (intervalLastIndex - intervalFirstIndex - numberOfEmptyPoints + 1);
|
||
|
||
// Second pass through inteval points required for calculations
|
||
pointTempValues[functionInfo.outputIndex] = 0;
|
||
for(int secondPassIndex = intervalFirstIndex; secondPassIndex <= intervalLastIndex; secondPassIndex++)
|
||
{
|
||
// Ignore empty points
|
||
if(series.Points[secondPassIndex].IsEmpty && this.IsEmptyPointIgnored)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
pointTempValues[functionInfo.outputIndex] +=
|
||
Math.Pow(series.Points[secondPassIndex].YValues[funcIndex-1] - average, 2);
|
||
}
|
||
|
||
// Divide by points number
|
||
pointTempValues[functionInfo.outputIndex] /=
|
||
intervalLastIndex - intervalFirstIndex - numberOfEmptyPoints + 1;
|
||
|
||
// If calculating the deviation - take a square root of variance
|
||
if(functionInfo.function == GroupingFunction.Deviation)
|
||
{
|
||
pointTempValues[functionInfo.outputIndex] =
|
||
Math.Sqrt(pointTempValues[functionInfo.outputIndex]);
|
||
}
|
||
}
|
||
|
||
// Increase current function index
|
||
++funcIndex;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// Checks the formula format and returns an array of formula types
|
||
/// for each X and each Y value of the input series.
|
||
/// </summary>
|
||
/// <param name="inputSeries">Array of input series.</param>
|
||
/// <param name="formula">Formula string.</param>
|
||
/// <param name="outputValuesNumber">Number of values in output series.</param>
|
||
/// <returns>Array of functions for each Y value.</returns>
|
||
private GroupingFunctionInfo[] GetGroupingFunctions(Series[] inputSeries, string formula, out int outputValuesNumber)
|
||
{
|
||
// Get maximum number of Y values in all series
|
||
int numberOfYValues = 0;
|
||
foreach(Series series in inputSeries)
|
||
{
|
||
numberOfYValues = (int)Math.Max(numberOfYValues, series.YValuesPerPoint);
|
||
}
|
||
|
||
// Allocate memory for the result array for X and each Y values
|
||
GroupingFunctionInfo[] result = new GroupingFunctionInfo[numberOfYValues + 1];
|
||
for(int index = 0 ; index < result.Length; index++)
|
||
{
|
||
result[index] = new GroupingFunctionInfo();
|
||
}
|
||
|
||
// Split formula by comma
|
||
string[] valueFormulas = formula.Split(',');
|
||
|
||
// At least one formula must be specified
|
||
if(valueFormulas.Length == 0)
|
||
{
|
||
throw (new ArgumentException(SR.ExceptionDataManipulatorGroupingFormulaUndefined));
|
||
}
|
||
|
||
// Check each formula in the array
|
||
GroupingFunctionInfo defaultFormula = new GroupingFunctionInfo();
|
||
foreach(string s in valueFormulas)
|
||
{
|
||
// Trim white space and make upper case
|
||
string formulaString = s.Trim();
|
||
formulaString = formulaString.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
|
||
|
||
// Get value index and formula type from the string
|
||
int valueIndex = 1;
|
||
GroupingFunction formulaType = ParseFormulaAndValueType(formulaString, out valueIndex);
|
||
|
||
// Save the default (first) formula
|
||
if(defaultFormula.function == GroupingFunction.None)
|
||
{
|
||
defaultFormula.function = formulaType;
|
||
}
|
||
|
||
// Check that value index do not exceed the max values number
|
||
if(valueIndex >= result.Length)
|
||
{
|
||
throw(new ArgumentException(SR.ExceptionDataManipulatorYValuesIndexExceeded( formulaString )));
|
||
}
|
||
|
||
// Check if formula for this value type was already set
|
||
if(result[valueIndex].function != GroupingFunction.None)
|
||
{
|
||
throw (new ArgumentException(SR.ExceptionDataManipulatorGroupingFormulaAlreadyDefined(formulaString)));
|
||
}
|
||
|
||
// Set formula type
|
||
result[valueIndex].function = formulaType;
|
||
}
|
||
|
||
// Apply default formula for non set X value
|
||
if(result[0].function == GroupingFunction.None)
|
||
{
|
||
result[0].function = GroupingFunction.First;
|
||
}
|
||
|
||
// Apply default formula for all non set Y values
|
||
for(int funcIndex = 1; funcIndex < result.Length; funcIndex++)
|
||
{
|
||
if(result[funcIndex].function == GroupingFunction.None)
|
||
{
|
||
result[funcIndex].function = defaultFormula.function;
|
||
}
|
||
}
|
||
|
||
// Specify output value index
|
||
outputValuesNumber = 0;
|
||
for(int funcIndex = 0; funcIndex < result.Length; funcIndex++)
|
||
{
|
||
result[funcIndex].outputIndex = outputValuesNumber;
|
||
|
||
if(result[funcIndex].function == GroupingFunction.HiLoOpCl)
|
||
{
|
||
outputValuesNumber += 3;
|
||
}
|
||
else if(result[funcIndex].function == GroupingFunction.HiLo)
|
||
{
|
||
outputValuesNumber += 1;
|
||
}
|
||
|
||
++outputValuesNumber;
|
||
}
|
||
|
||
// X value formula can be FIRST, LAST and AVE
|
||
if(result[0].function != GroupingFunction.First &&
|
||
result[0].function != GroupingFunction.Last &&
|
||
result[0].function != GroupingFunction.Center)
|
||
{
|
||
throw (new ArgumentException(SR.ExceptionDataManipulatorGroupingFormulaUnsupported));
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Parse one formula with optional value prefix.
|
||
/// Example: "Y2:MAX"
|
||
/// </summary>
|
||
/// <param name="formulaString">One formula name with optional value prefix.</param>
|
||
/// <param name="valueIndex">Return value index.</param>
|
||
/// <returns>Formula type.</returns>
|
||
private GroupingFunction ParseFormulaAndValueType(string formulaString, out int valueIndex)
|
||
{
|
||
// Initialize value index as first Y value (default)
|
||
valueIndex = 1;
|
||
|
||
// Split formula by optional ':' character
|
||
string[] formulaParts = formulaString.Split(':');
|
||
|
||
// There must be at least one and no more than two result strings
|
||
if(formulaParts.Length < 1 && formulaParts.Length > 2)
|
||
{
|
||
throw(new ArgumentException(SR.ExceptionDataManipulatorGroupingFormulaFormatInvalid( formulaString )));
|
||
}
|
||
|
||
// Check specified value type
|
||
if(formulaParts.Length == 2)
|
||
{
|
||
if(formulaParts[0] == "X")
|
||
{
|
||
valueIndex = 0;
|
||
}
|
||
else if(formulaParts[0].StartsWith("Y", StringComparison.Ordinal))
|
||
{
|
||
formulaParts[0] = formulaParts[0].TrimStart('Y');
|
||
|
||
if(formulaParts[0].Length == 0)
|
||
{
|
||
valueIndex = 1;
|
||
}
|
||
else
|
||
{
|
||
// Try to convert the rest of the string to integer
|
||
try
|
||
{
|
||
valueIndex = Int32.Parse(formulaParts[0], System.Globalization.CultureInfo.InvariantCulture);
|
||
}
|
||
catch(System.Exception)
|
||
{
|
||
throw (new ArgumentException(SR.ExceptionDataManipulatorGroupingFormulaFormatInvalid( formulaString )));
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
throw (new ArgumentException(SR.ExceptionDataManipulatorGroupingFormulaFormatInvalid( formulaString )));
|
||
}
|
||
}
|
||
|
||
// Check formula name
|
||
if(formulaParts[formulaParts.Length - 1] == "MIN")
|
||
return GroupingFunction.Min;
|
||
else if(formulaParts[formulaParts.Length - 1] == "MAX")
|
||
return GroupingFunction.Max;
|
||
else if(formulaParts[formulaParts.Length - 1] == "AVE")
|
||
return GroupingFunction.Ave;
|
||
else if(formulaParts[formulaParts.Length - 1] == "SUM")
|
||
return GroupingFunction.Sum;
|
||
else if(formulaParts[formulaParts.Length - 1] == "FIRST")
|
||
return GroupingFunction.First;
|
||
else if(formulaParts[formulaParts.Length - 1] == "LAST")
|
||
return GroupingFunction.Last;
|
||
else if(formulaParts[formulaParts.Length - 1] == "HILOOPCL")
|
||
return GroupingFunction.HiLoOpCl;
|
||
else if(formulaParts[formulaParts.Length - 1] == "HILO")
|
||
return GroupingFunction.HiLo;
|
||
else if(formulaParts[formulaParts.Length - 1] == "COUNT")
|
||
return GroupingFunction.Count;
|
||
else if(formulaParts[formulaParts.Length - 1] == "DISTINCTCOUNT")
|
||
return GroupingFunction.DistinctCount;
|
||
else if(formulaParts[formulaParts.Length - 1] == "VARIANCE")
|
||
return GroupingFunction.Variance;
|
||
else if(formulaParts[formulaParts.Length - 1] == "DEVIATION")
|
||
return GroupingFunction.Deviation;
|
||
else if(formulaParts[formulaParts.Length - 1] == "CENTER")
|
||
return GroupingFunction.Center;
|
||
|
||
// Invalid formula name
|
||
throw (new ArgumentException(SR.ExceptionDataManipulatorGroupingFormulaNameInvalid(formulaString)));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Checks if input/output series parameters are correct.
|
||
/// If not - fires an exception
|
||
/// </summary>
|
||
/// <param name="inputSeries">Input series array.</param>
|
||
/// <param name="outputSeries">Output series array.</param>
|
||
private void CheckSeriesArrays(Series[] inputSeries, Series[] outputSeries)
|
||
{
|
||
// At least one series must be in the input series
|
||
if(inputSeries == null || inputSeries.Length == 0)
|
||
{
|
||
throw (new ArgumentException(SR.ExceptionDataManipulatorGroupingInputSeriesUndefined));
|
||
}
|
||
|
||
// Output series must be empty or have the same number of items
|
||
if(outputSeries != null && outputSeries.Length != inputSeries.Length)
|
||
{
|
||
throw (new ArgumentException(SR.ExceptionDataManipulatorGroupingInputOutputSeriesNumberMismatch));
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Grouping overloaded methods
|
||
|
||
/// <summary>
|
||
/// Groups data using one or more formulas.
|
||
/// The series that is grouped is cleared of its original data, and used to store the new data points.
|
||
/// </summary>
|
||
/// <param name="formula">Grouping formula.</param>
|
||
/// <param name="interval">Interval size.</param>
|
||
/// <param name="intervalType">Interval type.</param>
|
||
/// <param name="inputSeries">Input series.</param>
|
||
public void Group(string formula,
|
||
double interval,
|
||
IntervalType intervalType,
|
||
Series inputSeries)
|
||
{
|
||
// Check arguments
|
||
if (inputSeries == null)
|
||
throw new ArgumentNullException("inputSeries");
|
||
|
||
Group(formula, interval, intervalType, inputSeries, null);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Groups data using one or more formulas.
|
||
/// Series are cleared of their original data and used to store the new data points.
|
||
/// </summary>
|
||
/// <param name="formula">Grouping formula.</param>
|
||
/// <param name="interval">Interval size.</param>
|
||
/// <param name="intervalType">Interval type.</param>
|
||
/// <param name="inputSeriesName">Comma separated list of input series names.</param>
|
||
public void Group(string formula,
|
||
double interval,
|
||
IntervalType intervalType,
|
||
string inputSeriesName)
|
||
{
|
||
// Check arguments
|
||
if (inputSeriesName == null)
|
||
throw new ArgumentNullException("inputSeriesName");
|
||
|
||
Group(formula, interval, intervalType, inputSeriesName, "");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Groups data using one or more formulas.
|
||
/// The series that is grouped is cleared of its original data, and used to store the new data points.
|
||
/// </summary>
|
||
/// <param name="formula">Grouping formula.</param>
|
||
/// <param name="interval">Interval size.</param>
|
||
/// <param name="intervalType">Interval type.</param>
|
||
/// <param name="intervalOffset">Interval offset size.</param>
|
||
/// <param name="intervalOffsetType">Interval offset type.</param>
|
||
/// <param name="inputSeries">Input series.</param>
|
||
public void Group(string formula,
|
||
double interval,
|
||
IntervalType intervalType,
|
||
double intervalOffset,
|
||
IntervalType intervalOffsetType,
|
||
Series inputSeries)
|
||
{
|
||
// Check arguments
|
||
if (inputSeries == null)
|
||
throw new ArgumentNullException("inputSeries");
|
||
|
||
Group(formula, interval, intervalType, intervalOffset, intervalOffsetType, inputSeries, null);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Groups data using one or more formulas.
|
||
/// Series are cleared of their original data and used to store the new data points.
|
||
/// </summary>
|
||
/// <param name="formula">Grouping formula.</param>
|
||
/// <param name="interval">Interval size.</param>
|
||
/// <param name="intervalType">Interval type.</param>
|
||
/// <param name="intervalOffset">Interval offset size.</param>
|
||
/// <param name="intervalOffsetType">Interval offset type.</param>
|
||
/// <param name="inputSeriesName">Comma separated list of input series names.</param>
|
||
public void Group(string formula,
|
||
double interval,
|
||
IntervalType intervalType,
|
||
double intervalOffset,
|
||
IntervalType intervalOffsetType,
|
||
string inputSeriesName)
|
||
{
|
||
// Check arguments
|
||
if (inputSeriesName == null)
|
||
throw new ArgumentNullException("inputSeriesName");
|
||
|
||
Group(formula, interval, intervalType, intervalOffset, intervalOffsetType, inputSeriesName, "");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Groups series data by axis labels using one or more formulas.
|
||
/// Output series are used to store the grouped data points.
|
||
/// </summary>
|
||
/// <param name="formula">Grouping formula.</param>
|
||
/// <param name="inputSeriesName">Comma separated list of input series names.</param>
|
||
/// <param name="outputSeriesName">Comma separated list of output series names.</param>
|
||
public void GroupByAxisLabel(string formula, string inputSeriesName, string outputSeriesName)
|
||
{
|
||
// Check arguments
|
||
if (inputSeriesName == null)
|
||
throw new ArgumentNullException("inputSeriesName");
|
||
|
||
GroupByAxisLabel(formula,
|
||
ConvertToSeriesArray(inputSeriesName, false),
|
||
ConvertToSeriesArray(outputSeriesName, true));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Groups a series' data by axis labels using one or more formulas.
|
||
/// The series is cleared of its original data, and then used to store the new data points.
|
||
/// </summary>
|
||
/// <param name="formula">Grouping formula.</param>
|
||
/// <param name="inputSeries">Input data series.</param>
|
||
public void GroupByAxisLabel(string formula, Series inputSeries)
|
||
{
|
||
// Check arguments
|
||
if (inputSeries == null)
|
||
throw new ArgumentNullException("inputSeries");
|
||
|
||
GroupByAxisLabel(formula, inputSeries, null);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Groups series data by axis labels using one or more formulas.
|
||
/// Each series that is grouped is cleared of its original data, and used to store the new data points.
|
||
/// </summary>
|
||
/// <param name="formula">Grouping formula.</param>
|
||
/// <param name="inputSeriesName">Comma separated list of input series names.</param>
|
||
public void GroupByAxisLabel(string formula, string inputSeriesName)
|
||
{
|
||
// Check arguments
|
||
if (inputSeriesName == null)
|
||
throw new ArgumentNullException("inputSeriesName");
|
||
|
||
GroupByAxisLabel(formula, inputSeriesName, null);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Groups series using one or more formulas.
|
||
/// Output series are used to store the grouped data points, and an offset can be used for intervals.
|
||
/// </summary>
|
||
/// <param name="formula">Grouping formula.</param>
|
||
/// <param name="interval">Interval size.</param>
|
||
/// <param name="intervalType">Interval type.</param>
|
||
/// <param name="intervalOffset">Interval offset size.</param>
|
||
/// <param name="intervalOffsetType">Interval offset type.</param>
|
||
/// <param name="inputSeriesName">Comma separated list of input series names.</param>
|
||
/// <param name="outputSeriesName">Comma separated list of output series names.</param>
|
||
public void Group(string formula,
|
||
double interval,
|
||
IntervalType intervalType,
|
||
double intervalOffset,
|
||
IntervalType intervalOffsetType,
|
||
string inputSeriesName,
|
||
string outputSeriesName)
|
||
{
|
||
// Check arguments
|
||
if (inputSeriesName == null)
|
||
throw new ArgumentNullException("inputSeriesName");
|
||
|
||
Group(formula,
|
||
interval,
|
||
intervalType,
|
||
intervalOffset,
|
||
intervalOffsetType,
|
||
ConvertToSeriesArray(inputSeriesName, false),
|
||
ConvertToSeriesArray(outputSeriesName, true));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Groups a series' data using one or more formulas.
|
||
/// An output series is used to store the grouped data points.
|
||
/// </summary>
|
||
/// <param name="formula">Grouping formula.</param>
|
||
/// <param name="interval">Interval size.</param>
|
||
/// <param name="intervalType">Interval type.</param>
|
||
/// <param name="inputSeries">Input data series.</param>
|
||
/// <param name="outputSeries">Output data series.</param>
|
||
public void Group(string formula,
|
||
double interval,
|
||
IntervalType intervalType,
|
||
Series inputSeries,
|
||
Series outputSeries)
|
||
{
|
||
// Check arguments
|
||
if (inputSeries == null)
|
||
throw new ArgumentNullException("inputSeries");
|
||
|
||
Group(formula, interval, intervalType, 0, IntervalType.Number, inputSeries, outputSeries);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Groups data for series using one or more formulas.
|
||
/// Output series are used to store the grouped data points.
|
||
/// </summary>
|
||
/// <param name="formula">Grouping formula.</param>
|
||
/// <param name="interval">Interval size.</param>
|
||
/// <param name="intervalType">Interval type.</param>
|
||
/// <param name="inputSeriesName">Comma separated list of input series names.</param>
|
||
/// <param name="outputSeriesName">Comma separated list of output series names.</param>
|
||
public void Group(string formula,
|
||
double interval,
|
||
IntervalType intervalType,
|
||
string inputSeriesName,
|
||
string outputSeriesName)
|
||
{
|
||
// Check arguments
|
||
if (inputSeriesName == null)
|
||
throw new ArgumentNullException("inputSeriesName");
|
||
|
||
Group(formula, interval, intervalType, 0, IntervalType.Number, inputSeriesName, outputSeriesName);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Groups a series using one or more formulas.
|
||
/// An output series is used to store the grouped data points, and an offset can be used for intervals.
|
||
/// </summary>
|
||
/// <param name="formula">Grouping formula.</param>
|
||
/// <param name="interval">Interval size.</param>
|
||
/// <param name="intervalType">Interval type.</param>
|
||
/// <param name="intervalOffset">Interval offset size.</param>
|
||
/// <param name="intervalOffsetType">Interval offset type.</param>
|
||
/// <param name="inputSeries">Input data series.</param>
|
||
/// <param name="outputSeries">Output data series.</param>
|
||
public void Group(string formula,
|
||
double interval,
|
||
IntervalType intervalType,
|
||
double intervalOffset,
|
||
IntervalType intervalOffsetType,
|
||
Series inputSeries,
|
||
Series outputSeries)
|
||
{
|
||
// Check arguments
|
||
if (inputSeries == null)
|
||
throw new ArgumentNullException("inputSeries");
|
||
|
||
Group(formula,
|
||
interval,
|
||
intervalType,
|
||
intervalOffset,
|
||
intervalOffsetType,
|
||
ConvertToSeriesArray(inputSeries, false),
|
||
ConvertToSeriesArray(outputSeries, false));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Groups a series' data by axis labels using one or more formulas.
|
||
/// An output series is used to store the grouped data points.
|
||
/// </summary>
|
||
/// <param name="formula">Grouping formula.</param>
|
||
/// <param name="inputSeries">Input data series.</param>
|
||
/// <param name="outputSeries">Output data series.</param>
|
||
public void GroupByAxisLabel(string formula, Series inputSeries, Series outputSeries)
|
||
{
|
||
// Check arguments
|
||
if (inputSeries == null)
|
||
throw new ArgumentNullException("inputSeries");
|
||
|
||
GroupByAxisLabel(formula,
|
||
ConvertToSeriesArray(inputSeries, false),
|
||
ConvertToSeriesArray(outputSeries, false));
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
}
|
||
|