Page 1 of 1
Functions and period
Posted: Wed Jan 11, 2017 3:06 am
by 16079247
Hi Support,
We have an issue with the function series, we are trying to populate a Add function series on a time series data based on a daily basis for which the code as follows:
Dim funcSeries As New Steema.TeeChart.Styles.FastLine(FChart.Chart)
funcSeries.Title = String.Format("Total ({0})", periodText)
funcSeries.DataSource = _selectedSeries
funcSeries.Marks.Visible = True
Dim chartTotalFunction As New Steema.TeeChart.Functions.Add
Dim period As New TimeSpan
period = New TimeSpan(1, 0, 0, 0)
chartTotalFunction.Period = period.TotalDays
chartTotalFunction.PeriodAlign = Steema.TeeChart.Functions.PeriodAligns.Center
chartTotalFunction.PeriodStyle = Steema.TeeChart.Functions.PeriodStyles.Range
funcSeries.Function = chartTotalFunction.Period
funcSeries.CheckDataSource()
The result of function series is based on intervals of one day from starting point (24 hours from starting), but not on based on the specific date. How to get the resulting values of the function series based on each date rather than a 24 hours day?
Re: Functions and period
Posted: Mon Jan 16, 2017 12:24 am
by 16079247
Hello..
Any input for this?
Re: Functions and period
Posted: Mon Jan 16, 2017 3:15 pm
by Christopher
Seveno Developer wrote:Hello..
Any input for this?
Sorry for the delay in this reply.
It seems there may be some defects in this area of code - I am looking at this now and will get back to you.
Re: Functions and period
Posted: Tue Jan 17, 2017 11:27 am
by Christopher
Hello,
Unfortunately there were two defects in this area of code which have now been fixed and will be available in the next maintenance release. However, these fixes can be used now in a custom Add function class like this:
Code: Select all
public class MyAdd : Add
{
public override double Calculate(Series source, int first, int last)
{
if (first == -1)
{
first = 0;
last = source.Count - 1;
}
List<double> tmpValues = new List<double>();
ValueList tmpSource = ValueList(source);
for (int i = first; i <= last; i++)
{
if (IncludeNulls || (!source.IsNull(i)))
{
AddValues(tmpValues, tmpSource[i]);
}
}
return CalculateValue(tmpValues.ToArray());
}
protected override void DoCalculation(Series source, ValueList notMandatorySource)
{
if (dPeriod == 0)
CalculateAllPoints(source, notMandatorySource);
else
CalculateByPeriodFix(source, notMandatorySource);
}
private bool HasRegularStep(ValueList list)
{
double step, laststep = 0;
for (int i = 1; i < list.Count; i++)
{
step = list[i] - list[i - 1];
if (i > 1 && Utils.SignificantDifference(laststep, step))
{
return false;
}
laststep = step;
}
return true;
}
private void CalculateByPeriodFix(Series source, ValueList notMandatorySource)
{
double tmpX;
int tmpLast;
double PosFirst;
double PosLast;
bool tmpCalc;
int tmpFirst = 0;
int tmpCount = source.Count;
double tmpBreakPeriod = notMandatorySource[tmpFirst];
DateTimeSteps tmpStep = Axis.FindDateTimeStep(dPeriod);
double actualStep = HasRegularStep(notMandatorySource) ? notMandatorySource[tmpFirst + 1] - tmpBreakPeriod : dPeriod * 0.001;
do
{
PosLast = 0;
if (PeriodStyle == PeriodStyles.NumPoints)
{
tmpLast = tmpFirst + Utils.Round(dPeriod) - 1;
PosFirst = notMandatorySource[tmpFirst];
if (tmpLast < tmpCount) PosLast = notMandatorySource[tmpLast];
}
else
{
tmpLast = tmpFirst;
PosFirst = tmpBreakPeriod;
Axis axis = Series.GetHorizAxis;
Series.GetHorizAxis.DateTimeIncrement(axis.Labels.ExactDateTime && axis.IsDateTime && (tmpStep >= DateTimeSteps.HalfMonth), true, ref tmpBreakPeriod, dPeriod, tmpStep);
PosLast = tmpBreakPeriod - (actualStep);
while (tmpLast < tmpCount - 1)
if (notMandatorySource[tmpLast + 1] < tmpBreakPeriod) tmpLast++;
else
break;
}
tmpCalc = false;
if (tmpLast < tmpCount)
{
/* align periods */
if (PeriodAlign == PeriodAligns.First)
tmpX = PosFirst;
else
if (PeriodAlign == PeriodAligns.Last)
tmpX = PosLast;
else
tmpX = (PosFirst + PosLast) * 0.5;
if ((PeriodStyle == PeriodStyles.Range) && (notMandatorySource[tmpFirst] < tmpBreakPeriod))
tmpCalc = true;
if ((PeriodStyle == PeriodStyles.NumPoints) || tmpCalc)
CalculatePeriod(source, tmpX, tmpFirst, tmpLast);
else
AddFunctionXY(true, tmpX, 0);
}
if ((PeriodStyle == PeriodStyles.NumPoints) || tmpCalc)
tmpFirst = tmpLast + 1;
} while (tmpFirst <= tmpCount - 1);
}
}
This class can be used as following:
Code: Select all
Line series;
FastLine funcSeries;
MyAdd chartTotalFunction;
private void InitializeChart()
{
funcSeries = new FastLine(tChart1.Chart);
funcSeries.Marks.Visible = true;
chartTotalFunction = new MyAdd();
chartTotalFunction.Period = new TimeSpan(0, 12, 0, 0).TotalDays;
chartTotalFunction.PeriodAlign = Steema.TeeChart.Functions.PeriodAligns.Last;
chartTotalFunction.PeriodStyle = Steema.TeeChart.Functions.PeriodStyles.Range;
funcSeries.Function = chartTotalFunction;
series = new Line(tChart1.Chart);
DateTime today = DateTime.Today;
for (int i = 0; i < 20; i++)
{
series.Add(today, i);
today = today.AddHours(3);
}
funcSeries.Marks.Visible = true;
series.Marks.Visible = true;
funcSeries.DataSource = series;
tChart1.Axes.Bottom.Labels.Angle = 90;
tChart1.Axes.Bottom.Increment = new TimeSpan(0, 3, 0, 0).TotalDays;
tChart1.Axes.Bottom.Labels.DateTimeFormat = "dd/MM/yy hh:mm";
}
which gives me this chart:
- 636202525670730716.jpg (76.64 KiB) Viewed 17175 times
The above chart is now correct. Can I help you with any specific questions you may have with this?
Re: Functions and period
Posted: Fri Jan 20, 2017 2:54 am
by 16079247
Hi Christopher,
Thank you.
Just wondering as we need to implement the other functions too and that we allow the users to add functions at run time from the chart editor, is there any way to modify the code defects so that it reflects for all functions? We do have access to the code for the latest build.
Re: Functions and period
Posted: Fri Jan 20, 2017 9:50 am
by Christopher
Seveno Developer wrote:Just wondering as we need to implement the other functions too and that we allow the users to add functions at run time from the chart editor, is there any way to modify the code defects so that it reflects for all functions? We do have access to the code for the latest build.
Of course. The changes are in Functions/Basic.cs:
- func1.PNG (13.9 KiB) Viewed 17151 times
- func2.PNG (33.54 KiB) Viewed 17151 times
You already have the code for HasRegularStep().
Re: Functions and period
Posted: Tue Jan 24, 2017 5:42 am
by 16079247
Hi Christopher,
Thanks for the code, we have updated the basic.cs accordingly but the results are still incorrect.
It skips values for the first day which has only 1 row.
Screenshot for sample data
- Sample data for the series
- Original_series_Data_source.png (30.68 KiB) Viewed 17135 times
We are using with chart max and total functions.
Output for total function:
- total function
- Total_irrelevant_value.png (31.49 KiB) Viewed 17135 times
Output for maximum function:
- Maximum_irrelevant_value.png (86.26 KiB) Viewed 17133 times
The results are correct when the subset of data for each day has the same number of data/ same interval (i.e date/time)
Re: Functions and period
Posted: Tue Jan 24, 2017 9:45 am
by Christopher
Seveno Developer wrote:
Thanks for the code, we have updated the basic.cs accordingly but the results are still incorrect.
The results are correct when the subset of data for each day has the same number of data/ same interval (i.e date/time)
Okay - would you please be so kind as to prepare a Minimal, Complete, and Verifiable example [
here] with which I can reproduce your issue here?
Re: Functions and period
Posted: Wed Jan 25, 2017 12:38 am
by 16079247
Hi Christopher,
We handle mostly time series data for which we need to be able to apply periodic functions. I am trying to make it simple and straight.
The forum does not allow adding text files, so I've sent the data into a .txt to your gmail address. Please use the text file to load the data for the series.
To reproduce the issue, first add a series in run time (it can be done using code too):
1. From the Chart editor, add a new series (i.e: RawDataSeries).
2. Under series Tab's General Tab, set the Horizontal Axis to Bottom and check Date Time checkbox (this is another bug as the date/time field is not recognized automatically, it throws an exception if not set manually)
3. Now under the series tab, click on Datasource, select text file
4. For the file attached here, under fields tab use Number of Header lines: 1, Separator: Tab, X: 0, Y: 1
5. Specify the file location, hit apply to populate the series
Now use the code that I have posted at the beginning. Please note the period we are using is One day and therefore the period = New TimeSpan(1, 0, 0, 0)
The total value should output individual total day's not on a 24 hours basis day. This does not work. In-fact, none of the function series' value for one day period is correct for the data given.
Hope that helps
Re: Functions and period
Posted: Thu Jan 26, 2017 5:26 pm
by Christopher
Seveno Developer wrote:
The total value should output individual total day's not on a 24 hours basis day. This does not work. In-fact, none of the function series' value for one day period is correct for the data given.
Hope that helps
Thanks.
I think the issue here is that you are expecting the function to group points by Date, whereas what they are doing is by PeriodStyles.Range, that is, the points that fall within a one day Period (in this case). Maybe the difference can be seen in this example:
Code: Select all
private void InitializeChart()
{
Func<string, List<Tuple<DateTime, double>>> GetData = (file) =>
{
List<Tuple<DateTime, double>> result = new List<Tuple<DateTime, double>>();
List<string> lines = File.ReadAllLines(file).ToList();
lines.RemoveAt(0);
foreach (var line in lines)
{
string[] splits = line.Split('\t');
DateTime date = DateTime.Parse(splits[0]);
double value = double.Parse(splits[1]);
result.Add(new Tuple<DateTime, double>(date, value));
}
return result;
};
List<Tuple<DateTime, double>> data = GetData(@"D:\FTP\data.txt");
FastLine funcSeries = new FastLine(tChart1.Chart);
Add chartTotalFunction = new Add();
TimeSpan period = new TimeSpan(1, 0, 0, 0);
chartTotalFunction.Period = period.TotalDays;
chartTotalFunction.PeriodAlign = Steema.TeeChart.Functions.PeriodAligns.Center;
chartTotalFunction.PeriodStyle = Steema.TeeChart.Functions.PeriodStyles.Range;
funcSeries.Function = chartTotalFunction;
Line series = new Line(tChart1.Chart);
for (int i = 0; i < data.Count; i++)
{
DateTime date = data[i].Item1;
double val = data[i].Item2;
series.Add(date, val);
}
funcSeries.Marks.Visible = true;
funcSeries.DataSource = series;
tChart1.Axes.Bottom.Labels.Angle = 90;
tChart1.Axes.Bottom.Labels.DateTimeFormat = "dd/MM/yy hh:mm";
FastLine funcSeriesLINQ = new FastLine(tChart1.Chart);
funcSeriesLINQ.Marks.Visible = true;
funcSeriesLINQ.Marks.Style = MarksStyles.XY;
var group = data.GroupBy(x => x.Item1.Date);
foreach (var item in group)
{
double sum = item.Sum(x => x.Item2);
funcSeriesLINQ.Add(item.Last().Item1, sum); //last date of group, but could calculate center
}
}
which gives me this:
- TChart636210480275437495.png (53.26 KiB) Viewed 17107 times
In funcSeriesLINQ we group the data by the Date, that is, by a one day (24 hour) period whereby all points are of the same day. The funcSeries, on the other hand, groups points into one day periods but not of the same day, because the first point does not start at 00:00. This is by design, although maybe not what you were expecting.
Re: Functions and period
Posted: Tue Jan 31, 2017 5:35 am
by 16079247
In funcSeriesLINQ we group the data by the Date, that is, by a one day (24 hour) period whereby all points are of the same day. The funcSeries, on the other hand, groups points into one day periods but not of the same day, because the first point does not start at 00:00. This is by design, although maybe not what you were expecting.
Thanks Christopher, the issue is as you pointed it correctly, the first point does not start at 00:00. I have added an overloading function to the datetime increment which solves our problem.
Thanks heaps for your help.
Cheers!