Recent

Author Topic: Chart.Extent or FuncSeries.Extent?  (Read 11423 times)

wp

  • Hero Member
  • *****
  • Posts: 13401
Chart.Extent or FuncSeries.Extent?
« on: September 23, 2012, 07:34:46 pm »
Writing a tutorial on TFuncSeries (http://wiki.lazarus.freepascal.org/TAChart_Tutorial:_TFuncSeries), I am stuck with the explanation of the Extent of a FuncSeries.

What is the difference to that of the Chart?

Suppose there are two FuncSeries in the chart, one has an x extent between -1 and 1, the other one between -2 and 2; the chart extent is not used. Both series are drawn between -2 and 2. Why is the extent of the first series ignored?

Then I set the chart's x extent to the range from -10 to 10. Now both series are drawn in this range, the series' extent is completely ignored.

What is the difference between the FuncSeries' extent and the chart's extent? What is the strategy to use one or the other?

Ask

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 687
Re: Chart.Extent or FuncSeries.Extent?
« Reply #1 on: September 23, 2012, 08:42:50 pm »
TChart.GetFullExtent function works as follows (see also the code):

1. Start from empty extent
2. For all series:
2.1 Get extent (in axis coordinates)
2.2 Convert it to graph coordinates
2.3 Join with the previous extent
3. For all axes:
3.1 Get range (in axis coordinates)
3.2 Convert it to graph coordinates
3.3 Join with the previous extent
4. For all edges of the current extent (in graph coordinates)
4.1 If the edge is "Used", override corresponding boundary of the calculated extent

So by setting extent of the series, you can expand the boundaries of the full extent.
By setting extent of the chart, you can enforce the boundary -- for example, to show only a part of the series.

Note also that full extent differs from current/logical extent -- the former is calculated based on chart data, while the latter is influenced by current viewport and modified by zooming/panning.

wp

  • Hero Member
  • *****
  • Posts: 13401
Re: Chart.Extent or FuncSeries.Extent?
« Reply #2 on: September 23, 2012, 10:41:23 pm »
Thank you for this explanation. I did some tests and verified this description. My understanding had been that the FuncSeries extent would define the range in which the function is calculated -- this seems to be wrong. I'd have to use domainexclusions to get an effect like in the attached image (constructed by means of lineseries).

wp

  • Hero Member
  • *****
  • Posts: 13401
Re: Chart.Extent or FuncSeries.Extent?
« Reply #3 on: September 23, 2012, 10:50:26 pm »
I tried to create the chart from the previous posting by means of function series and domain exclusions, but ran into a crash because the function is calculated at infinity in spite of domain exclusions. Is this a bug?

See attached demo. Undefine CHECKINF at the top of the unit to see the issue.
« Last Edit: September 23, 2012, 10:54:00 pm by wp »

Ask

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 687
Re: Chart.Extent or FuncSeries.Extent?
« Reply #4 on: September 24, 2012, 05:33:01 am »
Yes, I think I've added some bug in a recent refactoring, will investigate tonight.

Ask

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 687
Re: Chart.Extent or FuncSeries.Extent?
« Reply #5 on: September 25, 2012, 12:57:12 pm »
Should be fixed in r38825.

I have read your tutorial and fixed some typos. Thanks for a nice work.

I have few suggstions:
1) Probably a Step property should be discussed.
2) Maybe exclusion points should be added in a loop?
3) Is there a need to call AddPoint(0) after AddRange(NegInfinity, 0) ? If there is, it is a bug.
4) Perhaps DomainExclusions.Epsilon should be discussed -- although I am not sure about that.
« Last Edit: September 26, 2012, 02:42:31 am by Ask »

wp

  • Hero Member
  • *****
  • Posts: 13401
Re: Chart.Extent or FuncSeries.Extent?
« Reply #6 on: September 26, 2012, 08:59:44 am »
Thank you. You pointed out some topics that I wanted to include but had forgotten to. I'll add them when I have some time.

Quote
Is there a need to call AddPoint(0) after AddRange(NegInfinity, 0) ?

In fact, I did not even test because I thought that AddRange would define an interval without endpoints and I'd have to add the endpoints manually. If AddRange includes endpoints as I conclude from your answer there is no way to define domain exclusions for the function y = sqrt(x) correctly. This function is not defined for x < 0. So, if I call AddRange(NegInfinity, 0) I'd exclude the 0, but the function is defined at 0. Or is the a way to remove points from the rang?

Ask

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 687
Re: Chart.Extent or FuncSeries.Extent?
« Reply #7 on: September 26, 2012, 10:19:47 am »
Quote
AddRange would define an interval without endpoints
In the specific case of sqrt function, you can
Code: [Select]
AddRange(NegInfinity, 0); Epsilon := 0;
Of course, this does not solve the general case. Current design is, as usual, a compromise between simplicity and power. Full-blown implementation would include something like
Code: [Select]
AddRangeEx(ALeft, ARight: Double; ALeftOpen, ARightOpen: Boolean);plus separate Epsilon setting for each interval and rather non-trivial logic to merge and intersect arbitrary intervals.
Again, as usual, before moving far in this direction, I would like to get at least one user who needs this, to validate the design against real-life requirements.

wp

  • Hero Member
  • *****
  • Posts: 13401
Re: Chart.Extent or FuncSeries.Extent?
« Reply #8 on: September 27, 2012, 12:25:59 am »
To be mathematically exact, it would be fine to have a method "AddRangeWithoutBorder", I think it should not be too difficult to implement. But to be honest, even with the present AddRange it would be very difficult to see the missing x=0 point of the sqrt function.

Ask

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 687
Re: Chart.Extent or FuncSeries.Extent?
« Reply #9 on: September 27, 2012, 03:18:43 pm »
Quote
it would be fine to have a method "AddRangeWithoutBorder", I think it should not be too difficult to implement.
Currently, TIntervalList is implemented as an ordered list of (closed) non-overlapping intervals.
AddRange procedure automatically maintains these properties, which is important for efficient drawing.
To include open (and half-open) intervals, the data structure and logic should be correspondingly updated.
Not too hard, but not quite trivial either.

Notes on the last tutorial changes:
1) Meaning of then Epsilon property is different. I have added it to the documentation: http://wiki.lazarus.freepascal.org/TAChart_documentation#Function_series
2) Dynamic update of the function domain has some pitfalls:
2.1) It is better to use CurrentExtent, not LogicalExtent, because otherwise part of the series drawn over margins may not receive domain exclusion
2.2) I'd suggest using a single loop:
Code: [Select]
procedure TForm1.UpdateDomainExclusions;
var
  ex: TDoubleRect;
  x: Integer;
begin
  ex := Chart1.CurrentExtent;
  Chart1.DisableRedrawing;
  try
    with FuncSeries.DomainExclusions do begin
      Clear;
      for x := Floor(ex.a.x / Pi - 0.5) to Ceil(ex.b.x / Pi + 0.5) do
        AddPoint((x + 0.5) * Pi);
    end;
  finally
    Chart1.EnableRedrawing;
  end;
end;
2.3) Using OnExtentChanged is suboptimal. This event is called after the chart is drawn. The reason it works is that changing of domain exclusions initiates a redraw.
The reason it does not hang is that domain exclusions do not affect logical extent (unless ExtentAutoY = true. tAll in all, too brittle to recommend in tutorial.
Currently, you can use OnDrawBackWall event, although I admit it is not intuitive.


--

wp

  • Hero Member
  • *****
  • Posts: 13401
Re: Chart.Extent or FuncSeries.Extent?
« Reply #10 on: September 27, 2012, 03:39:43 pm »
Quote
Not too hard, but not quite trivial either.
No no - leave it as it is. Your updated documentation makes things a lot clearer.

I'll update the tutorial as soon as I can.

Ask

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 687
Re: Chart.Extent or FuncSeries.Extent?
« Reply #11 on: September 29, 2012, 07:42:27 am »
Since r38891 I have added OnExtentChanging event, which is called after the new extent is calculated, but before any drawing.

It should be useful both for updating domain exclusions and changing series detail level as discussed in a parallel thread.

wp

  • Hero Member
  • *****
  • Posts: 13401
Re: Chart.Extent or FuncSeries.Extent?
« Reply #12 on: September 29, 2012, 11:49:19 am »
Thank you. Updated the tutorial.

PeterX

  • Sr. Member
  • ****
  • Posts: 443
Re: Chart.Extent or FuncSeries.Extent?
« Reply #13 on: June 02, 2024, 11:20:15 am »
Writing a tutorial on TFuncSeries (http://wiki.lazarus.freepascal.org/TAChart_Tutorial:_TFuncSeries), ..
Page is empty.

Did this tutorial move anywhere else ?
usually using latest Lazarus release version with Windows 10 or 11

wp

  • Hero Member
  • *****
  • Posts: 13401

 

TinyPortal © 2005-2018