Recent

Author Topic: The best way to get the Yman and Ymin in the visible chart of the series  (Read 6841 times)

CM630

  • Hero Member
  • *****
  • Posts: 910
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
I need to get the Ymax and Ymin of the visible part of the series (for example series contain 1000 samples and with the current extents, only samples between 200 and 750 are displayed).
Probably writing such a function won't take much time, but if there is an inbuilt one, of course I would prefer it?
« Last Edit: November 23, 2012, 09:37:13 am by paskal »
Лазар 2,0,8; W10 or W7 64bit; FPC3,2,0; rev 62944

Ask

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 687
Re: The best way to get the Yman and Ymin in the visible chart of the series?
« Reply #1 on: November 21, 2012, 05:00:54 pm »
No, there is no built-in.
To write such a function, you must first define more precisely your requirements. In a general case, where data, extents and axis transformations may be arbitrary, the best you can do is a linear search
(code untested, but should give the general idea):

Code: [Select]
vymin := SafeInfinity; vymax := NegInfinity;
for i := 0 to Series1.Count - 1 do
  with Series1.Source[i]^ do
    if Chart1.IsPointInViewPort(Series1.AxisToGraph(Point)) then
      UpdateMinMax(Y, vymin, vymax);

Whether it is worth adding as a general function is doubtful -- perhaps as a kind of iterator...

CM630

  • Hero Member
  • *****
  • Posts: 910
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: The best way to get the Yman and Ymin in the visible chart of the series?
« Reply #2 on: November 22, 2012, 09:33:04 am »
So far I go with „Тhanks“, because it seems to work!

Whether it is worth adding as a general function is doubtful -- perhaps as a kind of iterator...
After reimplementing so many existing things for Lazarus, because I simply did not think that they might exist (while on the other hand Lazarus does not have an inbuilt function for such a basic tasks as splitting strings), I had to ask. TAChartt has to calculate these values anyway, while calculating extents for auto-scaling, so basically my question was if it give these values to the user.

Just to mention that SafeInfinity USES TAMath, and  NegInfinity uses math.
« Last Edit: November 22, 2012, 09:56:06 am by paskal »
Лазар 2,0,8; W10 or W7 64bit; FPC3,2,0; rev 62944

wp

  • Hero Member
  • *****
  • Posts: 7537
Quote
Lazarus does not have an inbuilt function for such a basic tasks as splitting strings
I don't know what you exactly mean by that, but if you mean splitting of strings at semicolons or tabs, I usually do that by means of a stringlist and its DelimitedText property. TStringList is very powerful.

   
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

Ask

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 687
See also Classes.ExtractStrings which has slightly more options.

CM630

  • Hero Member
  • *****
  • Posts: 910
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Now I found that the function, given by @Ask does not work as I need. It probably returns the maximum and minimum values of Y in the visible area.
What I need is: I have a curve, currently (i.e.) Xmin= 0,1; Xmax= 0,3; What are the maximum and the minimum values of the curve (data) itself, not the data fitted in the Y extents.
For example, if I have Y:=t*sin(t) the Ymax will be 1 and Ymin will be -1.
That is why I wrote that these values are calculated by the Chart anyway when autozooming.
I will try to write the function myself, if there is problem, I'll ask for help.

Also, I'd like to ask what does the ^ sign stand for? Googling it is hard.


I gave splitting string just as an example, there are plenty solutions, but the function itself is missing as a basic functionality.
I will check your offers, they might be useful for me.
« Last Edit: November 23, 2012, 10:01:03 am by paskal »
Лазар 2,0,8; W10 or W7 64bit; FPC3,2,0; rev 62944

wp

  • Hero Member
  • *****
  • Posts: 7537
Re: The best way to get the Yman and Ymin in the visible chart of the series
« Reply #6 on: November 23, 2012, 12:05:25 pm »
When your data are stored in a ListChartSource (like the built-in source of the typical series) then you can access its Extent property. You get the series' built-in chartsource by its ListSource property.

This will cover the entire data range; your first posting, however, suggested that you were interested only in a part of the range.

The character ^, in Pascal, stands for pointer and pointer dereferencing. Google for "pointer pascal"
« Last Edit: November 23, 2012, 12:27:34 pm by wp »
Mainly Lazarus trunk / fpc 3.2.0 / all 32-bit on Win-10, but many more...

CM630

  • Hero Member
  • *****
  • Posts: 910
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: The best way to get the Yman and Ymin in the visible chart of the series
« Reply #7 on: November 23, 2012, 02:21:56 pm »
I think that this way I will explain clearly what I need:
Let's say I have some array Y and
Y[0]=3;Y[1]=5;Y[2]=-2;Y[3]=16;Y[4]=-8;Y[5]=-3;Y[6]=9;Y[7]=12;Y[8]=3;Y[9]=5;Y[10]=-2;Y[11]=5;Y[12]=-7;
Then I do
for j:= 0 to 12 do Series1.AddXY(j,Y[j]);

After that I zoom in such a way that the Xmin (leftmost) value in the chart is 5 and the Xmax (rightmost) one is 9. The highest values in this interval is 9 and the lowest one is -3 and these are the values that I need.
This is quite a simplified case, because the numbers are added serially(for example there could be Series1.AddXY(3,Y[j]);  Series1.AddXY(1,Y[j]); Series1.AddXY(4,Y[j]);

[/i]While writing the explanation this way, things got clearer to me (until now I was thinking only about the first case). I have to scan all the samples in the series and to check if their X values are inside Xmin and Xmax and to pick the highest and the lowest values.

Edit: It's gotta be this, I'll test it next week:
Code: [Select]
function FindYMinMax (aSeries: TLineSeries; aXmin: Extended; aXmax: Extended): MaxMin;
var
   i: integer=0;
   Ymin,Ymax: Extended;
   XCurrent, YCurrent: Extended;
   YMet:Boolean=False;
   RetVal: TPoint;
begin
   for i:=0 to aSeries.Count-1 do
   begin
     XCurrent:=aSeries.GetXValue(i);
     YCurrent:=aSeries.GetYValue(i);
     if (XCurrent>=aXmin) and (XCurrent<=aXmax) then
       begin
         if YMet=False then //Init Ymin and Ymax
         begin
           YMet:=True;
           Ymin:=YCurrent;
           Ymax:=YCurrent;
         end
         else
         begin
           if Ymax<YCurrent then Ymax:=YCurrent;
           if Ymin>YCurrent then Ymin:=YCurrent;
         end;
       end;
   end;
   Result.Max:=Ymax;
   Result.Min:=Ymin;
end;
« Last Edit: November 23, 2012, 03:06:18 pm by paskal »
Лазар 2,0,8; W10 or W7 64bit; FPC3,2,0; rev 62944

Ask

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 687
Re: The best way to get the Yman and Ymin in the visible chart of the series
« Reply #8 on: November 23, 2012, 03:25:26 pm »
Yes, the general idea and your updated explanation both make sense.
Note that your code is somewhat cumbersome. Here is simpler version:
Code: [Select]
vymin := SafeInfinity; vymax := NegInfinity;
for p in Series1 do
  with Chart1.CurrentExtent do
    if InRange(Series1.AxisToGraph(p^.Point).X, a.X, b.X) then
      UpdateMinMax(p^.Y, vymin, vymax);
You can omit the call to the AxisToGraph if you have no rotations or transformations.

CM630

  • Hero Member
  • *****
  • Posts: 910
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: The best way to get the Yman and Ymin in the visible chart of the series
« Reply #9 on: November 26, 2012, 08:09:30 am »
Note that your code is somewhat cumbersome.
I was som thousands percent aware of that, mainly because of
Code: [Select]
if YMet=False then //Init Ymin and Ymax
         begin
           YMet:=True;
           Ymin:=YCurrent;
           Ymax:=YCurrent;
         end
Sure, I should have used +- infinity.  I found no documentation about Safeinfinity, what is its advantage comapred with Infinity? Maybe this will also hint me why you use (- SafeInfinity), instead of NegInfinity?

Also, InRange is not documented (AFAIK), too :(

I tried to make a function out of your code this way:
Code: [Select]
function FindYMinMax (aChart: TChart; SeriesIndex: Word): TNearestPointParams;
var
  vYmin,vYmax: Extended;
  p: TNearestPointParams;  //Should it be TComponent or something else
begin
 vYmin := SafeInfinity; vYmax := NegInfinity;
 for p in aChart.Series[SeriesIndex] do
   with aChart.CurrentExtent do
     if InRange(TLineSeries(aChart.Series[SeriesIndex]).AxisToGraph([b]p^.Point).X, a.X, b.X) then
       UpdateMinMax(p^.Y, vYmin, vYmax);
end; 
Result:=p;
But I got errors. So I changed  p: TNearestPointParams; to p: TComponent; which resulted in an error less, but still I get Error: Illegal qualifier at p^.

Лазар 2,0,8; W10 or W7 64bit; FPC3,2,0; rev 62944

CM630

  • Hero Member
  • *****
  • Posts: 910
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: The best way to get the Yman and Ymin in the visible chart of the series
« Reply #10 on: November 26, 2012, 08:10:02 am »
Note that your code is somewhat cumbersome.
I was some thousands percent aware of that, mainly because of
Code: [Select]
if YMet=False then //Init Ymin and Ymax
         begin
           YMet:=True;
           Ymin:=YCurrent;
           Ymax:=YCurrent;
         end
Sure, I should have used +- infinity.  I found no documentation about Safeinfinity, what is its advantage comapred with Infinity? Maybe this will also hint me why you use  NegInfinity, instead of (- SafeInfinity)?

Also, InRange is not documented (AFAIK), too :(

I tried to make a function out of your code this way:
Code: [Select]
function FindYMinMax (aChart: TChart; SeriesIndex: Word): TNearestPointParams;
var
  vYmin,vYmax: Extended;
  p: TNearestPointParams;  //Should it be TComponent or something else
begin
 vYmin := SafeInfinity; vYmax := NegInfinity;
 for p in aChart.Series[SeriesIndex] do
   with aChart.CurrentExtent do
     if InRange(TLineSeries(aChart.Series[SeriesIndex]).AxisToGraph([b]p^.Point).X, a.X, b.X) then
       UpdateMinMax(p^.Y, vYmin, vYmax);
end; 
Result:=p;
But I got errors. So I changed  p: TNearestPointParams; to p: TComponent; which resulted in an error less, but still I get Error: Illegal qualifier at p^.
« Last Edit: November 26, 2012, 08:12:29 am by paskal »
Лазар 2,0,8; W10 or W7 64bit; FPC3,2,0; rev 62944

Ask

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 687
Re: The best way to get the Yman and Ymin in the visible chart of the series
« Reply #11 on: November 26, 2012, 08:18:38 am »
Quote
I found no documentation about Safeinfinity, what is its advantage comapred with Infinity?
It does not gives compiler errors in range-check mode for older FPC compilers.
Basically, you can ignore it and use Infinity if you use recent enough FPC compiler.

Quote
InRange is not documented
It is: http://www.freepascal.org/docs-html/rtl/math/inrange.html

Quote
still I get Error: Illegal qualifier at p^
You should declare it as PChartDataItem. Simplest way to do so is to use code completion
(usually activated by Ctrl+Shift+C hotkey).

CM630

  • Hero Member
  • *****
  • Posts: 910
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: The best way to get the Yman and Ymin in the visible chart of the series
« Reply #12 on: November 26, 2012, 09:39:22 am »
Quote
InRange is not documented
It is: http://www.freepascal.org/docs-html/rtl/math/inrange.html
Thanks, I thought it was a TAChart function, only.

Quote
still I get Error: Illegal qualifier at p^

You should declare it as PChartDataItem. Simplest way to do so is to use code completion
(usually activated by Ctrl+Shift+C hotkey).

So I did
 p: PChartDataItem;
  but then I get
Error: Incompatible types: got "TComponent" expected "PChartDataItem"
on line
for p in aChart.Series[SeriesIndex] do.

Using code completion resulted in p: TComponent; but I already wrote what happens in that case.
I think that I should use
TLineSeries(aChart.Series[SeriesIndex])) but anyway it did not help. I tried to cast
for p in  PChartDataItem(TLineSeries(aChart.Series[SeriesIndex])) do
but it resulted in
Error: Cannot find an enumerator for the type "PChartDataItem"

« Last Edit: November 26, 2012, 09:43:46 am by paskal »
Лазар 2,0,8; W10 or W7 64bit; FPC3,2,0; rev 62944

Ask

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 687
Re: The best way to get the Yman and Ymin in the visible chart of the series
« Reply #13 on: November 26, 2012, 10:27:35 am »
Ah, sorry, that was a typo.
You need to write
Code: [Select]
for p in TChartSeries(aChart.Series[SeriesIndex]).Source do

CM630

  • Hero Member
  • *****
  • Posts: 910
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: The best way to get the Yman and Ymin in the visible chart of the series
« Reply #14 on: November 27, 2012, 01:53:03 pm »
Now it compiles, but it seems to me, that it does not take the Max and Min only in the visible X area, but for the entire X rage.
So far I went on with my code, probably later I shall spare some time for @ask'2 one.
Лазар 2,0,8; W10 or W7 64bit; FPC3,2,0; rev 62944

 

TinyPortal © 2005-2018