Page 1 of 1

Bug in TErrorSeries?

Posted: Tue Sep 28, 2010 2:52 pm
by 16556687
Can anybody tell me if this is a bug in TeeChart Pro 2010/Delphi 2010, or if I possibly overlooked a setting option?

I created a TChart with a TPointSeries and a TErrorSeries, to draw points with error bars in Y direction (vertical). The TChart has a logarithmic Y axis which is set to "automatic scaling". The numerical error dY entered into the TErrorSeries is of course the same for the upper part and the lower part of the error bar, but due to the logarithmic axis, the upper part should look much shorter than the lower part in the graphics. However, both parts are plotted with the same length. I checked the end points of the two parts of the error bars. The length of the upper part (in cm) appears to be calculated correctly. But then this length (in cm) is also used for the lower part, which should be much longer. At least internally, TeeChart seems to have calculated the proper length of the lower error bar part, because the automatic Y axis scaling jumps to a new Y-minimum value, that corresponds to the point where the lower error bar part should end, if it was drawn correctly.

Thanks for any help!

Re: Bug in TErrorSeries?

Posted: Wed Sep 29, 2010 10:45 am
by narcis
Hi Uwe,

I suspect this is because of the fix for TV52014260/TF02014259 which was discussed here otherwise what is described in that thread would occur.

Re: Bug in TErrorSeries?

Posted: Thu Sep 30, 2010 8:18 am
by 16556687
Hi Narcis,

Thanks for the info. I'm not sure if my bug is actually connected with the bug described in the link you sent me. Of course I don't know the inner secrets of TeeChart, but my personal speculation of what happens is this (please correct me if I'm wrong):
You first calculate the length of the top part of the error bar in pixels, and draw it. (I have checked this by printing the final TChart, measuring the length of the error bar in cm, and comparing it to where it should actually end with the given Y and Error value => top part is always OK). But then, you use the same number of pixels for drawing the bottom part. This is only correct on a linear axis. On a logarithmic axis, the length of the bottom part (in pixels) has to be longer - that's just mathematics. I therefore suggest that you always simply repeat the existing calculation "Y + Error => number of pixels for top part" for the bottom part: "Y - Error => different number of pixels for bottom part". And that's it!!! It should work no matter if the axis is linear or log. The space for this longer bottom part of the error bar on the Y axis is already correctly prepared (according to my measurement on the print) - probably that's the result of the bugfix from the link.

There is also another bug which I would like to report for the TErrorSeries. When using the TErrorSeries with a log Y-scale, I sometimes only want to plot a half error bar above the point, but not the other part below the point, using "ErrorStyle=essTop". But even then, the automatic scaling makes space below the points for a lower error bar part, that will never be drawn (and vice versa for an upper part with "ErrorStyle=essBottom"). This unnecessarily squeezes the curve to the top (of bottom) of the TChart, with lots of unused empty space on the other side. It seems as if the internal routine of TErrorBar always proceeds the full calculation and auto scaling for both error bar parts, and then only skips the drawing of one or the other error bar part, according to the value of "ErrorStyle=ess....". This should also be changed.

And finally, there is still another minor bug with TErrorBar that I noticed now. This bug appears to be independent from lin or log scale.
I only want to draw half error bars above the points:

ErrorSeriesAbove: TErrorSeries
...
ErrorSeriesAbove.ErrorStyle:= essTop
ErrorSeriesAbove.AddErrorBar(X, Y, E);

The error value "E" should normally supposed to be E > 0. But if Y < 0, then with E > 0 the half error bar is drawn below the point, inspite of the "essTop" setting.

A little workaround can avoid this problem:

E:= Abs(E) // to have always positive values
if Y>0 then
ErrorSeriesAbove.AddErrorBar(X, Y, E)
else
ErrorSeriesAbove.AddErrorBar(X, Y, -E);

But if you (hopefully !!!) touch the TErrorBar anyway now, then maybe you could solve this little issue as well.

Thanks. Regards, Uwe

Re: Bug in TErrorSeries?

Posted: Fri Oct 01, 2010 2:32 pm
by narcis
Hi Uwe,
Thanks for the info. I'm not sure if my bug is actually connected with the bug described in the link you sent me. Of course I don't know the inner secrets of TeeChart, but my personal speculation of what happens is this (please correct me if I'm wrong):
You first calculate the length of the top part of the error bar in pixels, and draw it. (I have checked this by printing the final TChart, measuring the length of the error bar in cm, and comparing it to where it should actually end with the given Y and Error value => top part is always OK). But then, you use the same number of pixels for drawing the bottom part. This is only correct on a linear axis. On a logarithmic axis, the length of the bottom part (in pixels) has to be longer - that's just mathematics. I therefore suggest that you always simply repeat the existing calculation "Y + Error => number of pixels for top part" for the bottom part: "Y - Error => different number of pixels for bottom part". And that's it!!! It should work no matter if the axis is linear or log. The space for this longer bottom part of the error bar on the Y axis is already correctly prepared (according to my measurement on the print) - probably that's the result of the bugfix from the link.
Ok, I see. That was just a step beyond TV52014260. So I have already fixed this issue (TV52015184) for the next maintenance release. I can send you ErrorBar.pas with the modifications so that you can test it at your end. Using this code snippet:

Code: Select all

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  Series1.ErrorStyle:=essTopBottom;
  Chart1.Axes.Left.Logarithmic:=True;
  //Chart1.Axes.Left.Inverted:=True;
  Chart1.AddSeries(TPointSeries.Create(Self));

  for i:=0 to 10 do
  begin
    Series1.AddErrorBar(i, i*10, 10);
    Chart1[1].AddXY(i, i*10);
  end;
end;
I get this chart:
ErrorBarLog.jpg
ErrorBarLog.jpg (58.75 KiB) Viewed 6266 times
Is this what you expected?
There is also another bug which I would like to report for the TErrorSeries. When using the TErrorSeries with a log Y-scale, I sometimes only want to plot a half error bar above the point, but not the other part below the point, using "ErrorStyle=essTop". But even then, the automatic scaling makes space below the points for a lower error bar part, that will never be drawn (and vice versa for an upper part with "ErrorStyle=essBottom"). This unnecessarily squeezes the curve to the top (of bottom) of the TChart, with lots of unused empty space on the other side. It seems as if the internal routine of TErrorBar always proceeds the full calculation and auto scaling for both error bar parts, and then only skips the drawing of one or the other error bar part, according to the value of "ErrorStyle=ess....". This should also be changed.
Yes, I have been able to reproduce this one and added the defect to the bug list (TV52015186) to be fixed.
And finally, there is still another minor bug with TErrorBar that I noticed now. This bug appears to be independent from lin or log scale.
I only want to draw half error bars above the points:

ErrorSeriesAbove: TErrorSeries
...
ErrorSeriesAbove.ErrorStyle:= essTop
ErrorSeriesAbove.AddErrorBar(X, Y, E);

The error value "E" should normally supposed to be E > 0. But if Y < 0, then with E > 0 the half error bar is drawn below the point, inspite of the "essTop" setting.

A little workaround can avoid this problem:

E:= Abs(E) // to have always positive values
if Y>0 then
ErrorSeriesAbove.AddErrorBar(X, Y, E)
else
ErrorSeriesAbove.AddErrorBar(X, Y, -E);

But if you (hopefully !!!) touch the TErrorBar anyway now, then maybe you could solve this little issue as well.
Ok, I fixed this one (TV52015187) too.

Re: Bug in TErrorSeries?

Posted: Mon Oct 04, 2010 7:38 am
by 16556687
Hi Narcis,
Thanks for the news. The TChart plot you show for TV52015184 (longer error bars on botton) looks perfect. When will the revised version with the 3 bug fixes be available?
Regards, Uwe

Re: Bug in TErrorSeries?

Posted: Mon Oct 04, 2010 11:27 am
by narcis
Hi Uwe,

TV52015186 has not been fixed yet. We are now making the very last changes in v2010.01 before code freeze. I'm afraid we won't have the time to include TV52015186 in it. We will test the installers and hopefully publish the version before the end of the week.

Re: Bug in TErrorSeries?

Posted: Thu Dec 30, 2010 12:40 pm
by narcis
Hi Uwe,

Just wanted to inform that I have fixed TV52015186 for next TeeChart 2010 VCL maintenance release. In the meantime you can implement the fix in ErrorBar.pas implementing TCustomErrorSeries.MaxYValue and TCustomErrorSeries.MinYValue methods like this:

Code: Select all

Function TCustomErrorSeries.MaxYValue:Double;
Var t      : Integer;
    tmp    : Double;
    tmpErr : Double;
Begin
  if IDrawBar then result:=inherited MaxYValue else result:=0;
  for t:=0 to Count-1 do
  if IDrawBar then
  Begin
    tmpErr:=FErrorValues.Value[t];
    tmp:=YValues.Value[t];
    if tmp<0 then tmp:=tmp-tmpErr else tmp:=tmp+tmpErr;
    if tmp>result then result:=tmp;
  end
  else
  begin
    tmp:=YValues.Value[t];

    if ((ErrorStyle=essTop) and not GetVertAxis.Inverted) or
        (ErrorStyle=essTopBottom) then
      tmp:=tmp+FErrorValues.Value[t];

    if t=0 then
       result:=tmp
    else
       result:=Math.Max(result,tmp);
  end;
End;

Function TCustomErrorSeries.MinYValue:Double;
Var t      : Integer;
    tmp    : Double;
    tmpErr : Double;
Begin
  if IDrawBar then result:=inherited MinYValue else result:=0;
  for t:=0 to Count-1 do
  if IDrawBar then
  Begin
    tmpErr:=FErrorValues.Value[t];
    tmp:=YValues.Value[t];
    if tmp<0 then tmp:=tmp-tmpErr else tmp:=tmp+tmpErr;
    if tmp<result then result:=tmp;
  end
  else
  begin
    tmp:=YValues.Value[t];

    if ((ErrorStyle=essBottom) and not GetVertAxis.Inverted) or
        (ErrorStyle=essTopBottom) then
      tmp:=tmp-FErrorValues.Value[t];

    if t=0 then
       result:=tmp
    else
       result:=Math.Min(result,tmp);
  end;
End;

Re: Bug in TErrorSeries?

Posted: Mon Jan 03, 2011 8:12 am
by 16556687
Thanks a lot!!!
Best regards, and a happy new year,
Uwe