1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- // See the LICENSE file in the project root for more information.
- //
- // 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.
- //
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Data;
- namespace FastReport.DataVisualization.Charting
- {
- #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>
- 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>
- 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
- }
- }
|