TAChart spline series: how to return Y value for a given X value? lazarus / 55-TAChart ---------------------------------------------------------------------- ironphil · 2011-09-10 23:26 I am using both the Bspline and cubic spline series with TAChart and they work like a charm. However, since I use the spline to modelize some background, I eventually need to get the Y value of the spline at a specific X value (which is not necessarily at a source point) in order to subtract the background. Is there a way to retrieve the Y value of the curve for a given X value? ---------------------------------------------------------------------- Ask · 2011-09-11 10:26 Use Calculate function since r32282 ---------------------------------------------------------------------- ironphil · 2011-09-11 23:39 Perfect! It works just as expected. Thank you. ---------------------------------------------------------------------- bobihot · 2014-04-06 23:52 Hi, I need of this, but can not solve by self. Are You can give me some demo code? ( To get Y value, from X ) Thanks ---------------------------------------------------------------------- wp · 2014-04-07 08:09 Code: [Select]procedure TForm1.Button1Click(Sender: TObject); var   x, y: Double; begin   x := 1.0;   y := Chart1CubicSplineSeries1.Calculate(x);   ShowMessage(Format('The spline value for x = %f is %f', [x, y])); end;   Is that what you want? ---------------------------------------------------------------------- bobihot · 2014-04-07 08:49 That this, but with TBSplineSeries do not work. Also NearestgraphPoint. With TCubicSplineSeries they work fine? Thanks I was try with this sample: ---------------------------------------------------------------------- wp · 2014-04-07 09:03 You are right, a "TBSplineSerie.Calculate()" had not been implemented. Let me see if I can fix this. But be patient, I have to dive into code that I have not written myself... ---------------------------------------------------------------------- wp · 2014-04-12 19:25 Trunk rev 44706 contains now a Calculate method for TBSplineSeries which allows to calculate the interpolated spline value for any x value within the series extent. The calculation is done by interpolation between tabulated values, so please don't expect ultimate precision... Anyway, this does not solve your problem of tracking the interpolated values with the crosshair cursor. And I am a bit confused what to do about that. The problem is that TBSplineSeries, in my opinion, behaves correctly with respect to the DataPointCrosshairTool. In all TAChart series, the cursor jumps only to "real" data points. The exception is CubicSplineSeries where the cursor follows the interpolated points and does not lock to the "real" data points. In my feeling, this behavior is wrong, and I am thinking about removing the curve tracking feature of the CubicSplineSeries, at least optionally, to get a consistent behavior of all series. ---------------------------------------------------------------------- bobihot · 2014-04-13 10:43 Thanks- I will be try now. CubicSplineSeries pass by initial points and do not have difference to spline line. Instead of B-spline, where passed inside. Now I try and write conclusion If I understand what-where can to do, will try to change some thing. In my case I need to recover noise signal and this mean that maybe B-spline is a real signal, which is need to track. Very, very thanks!  P.M. Why new snapshots is with fpc-2.6.2 ? I exchange with 2.6.4 and work very well. ---------------------------------------------------------------------- wp · 2014-04-13 12:54 In the attachment you can find a modified version of your demo which, as a workaround, uses an invisible line series that copies the calculated B-Spline points by means of a UserDefinedChartSource recalculating the interpolated points of the BSplineSeries at some intervals. I also tried a TFunctionSeries but this crashes due to NaN's being returned from BSplineSeries.Calculate for non-existing x values. ---------------------------------------------------------------------- Relativity · 2016-06-01 14:04 QuoteI also tried a TFunctionSeries but this crashes due to NaN's being returned from BSplineSeries.Calculate for non-existing x values. wp, what do you mean with "non-existing x values" ? Do you mean x values that have not been inserted in the ListChartSource used as source for the BSplineSeries ? ---------------------------------------------------------------------- wp · 2016-06-01 15:38 Sorry - I can't rember exactly, two years is a long time... But I think that the BSplineSeries is calculated only within a given extent of x values, in the example between 10 and 16. For all other x values the Calculate method of TBSplineSeries returns NaN ("Not a Number") which causes errors in some cases. ---------------------------------------------------------------------- Relativity · 2016-06-02 09:11 I get a runtime error when I use TBSplineSeries.Calculate in the following code: Code: [Select]   BSpline.Degree := 3;    ListChartSource1 := TListChartSource.Create(Chart1);    ListChartSource2 := TListChartSource.Create(Chart1);    ListChartSource3 := TListChartSource.Create(Chart1);    for i := -200 to 1500 do      begin        ListChartSource1.Add(i,rohDataSum[i]);        ListChartSource2.Add(i,rohDataSum[i]/520.02);      end;   BSpline.Source:= ListChartSource1;   CubicSpline.Source := ListChartSource1;   CoMoIps.Source := ListChartSource1;   j:=BSpline.GetYValue(202); // THIS WORKS   j:= BSpline.Calculate(202); // HERE I GET RUNTIME ERROR        The statement before the last one: Code: [Select]j:=BSpline.GetYValue(202); works perfectly and returns the right value (I've checked with the debugger), but the last statement: Code: [Select]j:=BSpline.Calculate(202); gives runtime error. Can anybody help me ? ---------------------------------------------------------------------- wp · 2016-06-02 09:42 Quote from: Relativity on June 02, 2016, 11:11:28 amCan anybody help me ? Not without any more details. Your code looks correct, but there are many reasons why something could go wrong. Please condense the topic into a small compilable project which shows the issue and which you upload here (only pas, lfm, lpi and lpr files, packed into a single zip). ---------------------------------------------------------------------- Relativity · 2016-06-02 11:40 Here is a project with an example of the problem: GetYValue works but Calculate doesn't. Thank you for everything. ---------------------------------------------------------------------- wp · 2016-06-02 12:46 Your chart already contains a Chart1BSplineSeries1 and a ListChartSource1 created at designtime - you see this in the object tree above the object inspector. But you create them a second time at runtime in the OnCreate event of the form. Normally this is no problem, but you make two mistakes: You give the runtime-created BSplineSeries and ListChartSource the same names as the already existing ones. This creates a memory leak because the already existing object no longer can be accessed and destroyed.You do not add the newly created series to the chart, you must call Chart.AddSeries. Therefore, the series does not know the chart to which it belongs, and this finally causes the crash you observe. Don't confuse this with the "owner" that you specify in the constructor. The "owner" is responsible for destroying an object when the program end. Therefore, it is not needed to explicitly destroy these manually created objects in FormDestroy.This is the modification required your program to run: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.FormCreate(Sender: TObject);var  i : Integer;begin//  Chart1BSplineSeries1 := TBSplineSeries.Create(Chart1);  // already created at design-time!//  ListChartSource1 := TListChartSource.Create(Chart1);  for i := -200 to 1500 do    ListChartSource1.Add(i,4*i);   Chart1BSplineSeries1.Source := ListChartSource1;end; And, as mentioned, remove the FormDestroy method. And this is the alternative code to correctly create series and listsource at runtime: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.FormCreate(Sender: TObject);var  i: Integer;begin  ListChartSource1 := TListChartSource.Create(self);    // better to use the form as "owner". Source can be shared between several charts this way!  for i := -200 to 1500 do    ListChartSource1.Add(i,4*i);   Chart1BSplineSeries1 := TBSplineSeries.Create(Chart1);  // set properties, e.g.:  Chart1BSplineSeries1.Title := 'B-Spline';  Chart1BSplineSeries1.Source := ListChartSource;  Chart1.AddSeries(Chart1BSplineSeries);end;But remove the design-time created series and source if you'd decide to go this way. ---------------------------------------------------------------------- Relativity · 2016-06-06 08:13 I have implemented your second option, to correctly create series and listsource in runtime. It perfectly works. Thank you for your time. You really know the ropes.