Proposed patches for TCHartSeries.Datasource property

TeeChart VCL for Borland/CodeGear/Embarcadero RAD Studio, Delphi and C++ Builder.
Post Reply
h.hasenack
Newbie
Newbie
Posts: 32
Joined: Tue Jul 21, 2009 12:00 am
Location: Nijmegen, Netherlands

Proposed patches for TCHartSeries.Datasource property

Post by h.hasenack » Fri Jul 24, 2009 11:49 am

The Datasource property clashes with the Datasourceslist property. The datasourceslist is stored using the defineproperties method, and only when Datasources.COunt>1.

The problem is that the datasource property is always stored, causing an overwrite :shock: of the earlier loaded datasources list when the chart series setup is loaded later on.
Therefore the datasource property should be defined as

Code: Select all

property DataSource:TComponent read GetDataSource write SetDataSource stored StoreDatasource;
and private function StoreDatasource should be implemented as follows:

Code: Select all

function TChartSeries.StoreDatasource:boolean;
begin
  Result:=DataSources.Count=1;
end;
Also something should happen to the TChartSeries.Notification method which causes the datasources list to runs out of sync :x when series are destroyed. Only the Datasource property is checked in the original code, and the datasources list is forgotten :roll: .

Code: Select all

procedure TChartSeries.Notification( AComponent: TComponent;
                                     Operation: TOperation);
begin
  inherited;
  if Operation=opRemove then
{$ifdef HH_PATCH_TC_DATASOURCE}
  begin
{$endif}
     if AComponent=FTeeFunction then
        FTeeFunction:=nil
     else
{$ifdef HH_PATCH_TC_DATASOURCE}
      // Update Datasources list
      if assigned(Datasources) and (Datasources.IndexOf(AComponent)>=0) then
      begin
        DataSources.Remove(AComponent);
      end;
{$else}
      { if "AComponent" is the same as series datasource,
        then set datasource to nil }
     if AComponent=DataSource then
        InternalRemoveDataSource(AComponent);  // 7.0
{$endif}
{$ifdef HH_PATCH_TC_DATASOURCE}
  end;
{$endif}
end;
Finally there is another bug in the datasources handling. When there are multiple datasources and the first one is empty, the depending series are not or wrongly displayed. For this I patched the TCHartSeries.GetDatasource method so it will primarily return the first datasource containing data points. And falls back to the original, returning Datasources[0] or nil.

Code: Select all

Function TChartSeries.GetDataSource:TComponent;
VAR i:integer;
begin
  Result:=nil;
  if Assigned(FDataSources) and (FDataSources.Count>0) then
  begin
    for i:=0 to FDataSources.Count-1 do
    begin
      if TChartSeries(FDataSources[i]).Count>0 then
      begin
        Result:=TChartSeries(FDataSources[i]);
        break; // found a series with data
      end;
    end;
    if not assigned(Result) then 
      result:=FDataSources[0];
  end;
end;
Regards - Hans

Yeray
Site Admin
Site Admin
Posts: 9602
Joined: Tue Dec 05, 2006 12:00 am
Location: Girona, Catalonia
Contact:

Re: Proposed patches for TCHartSeries.Datasource property

Post by Yeray » Mon Jul 27, 2009 3:13 pm

Hi Hans,

If I understand well the following code should reproduce the issues you are explaining. But I can't reproduce it with v8.

Code: Select all

var Bar1, Bar2, Bar3: TBarSeries;
    Line1: TLineSeries;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  Chart1.View3D := false;

  Bar1 := TBarSeries.Create(self);
  Bar2 := TBarSeries.Create(self);
  Bar3 := TBarSeries.Create(self);
  Chart1.AddSeries(Bar1);
  Chart1.AddSeries(Bar2);
  Chart1.AddSeries(Bar3);

  Line1 := TLineSeries.Create(self);
  Chart1.AddSeries(Line1);
  Line1.FunctionType := TAverageTeeFunction.Create(self);

  for I := 0 to 4 do
  begin
    Bar1.Add(100);
    Bar2.Add(200);
    Bar3.Add(300);
  end;

  Line1.DataSources.Add(Bar1);
  Line1.DataSources.Add(Bar2);
  Line1.DataSources.Add(Bar3);
  Line1.CheckDataSource;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Line1.DataSource := Bar3;
  Line1.CheckDataSource;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  Bar1.Clear;
  Line1.CheckDataSource;
end;
After loading the chart, the average function shows the average of the three functions (DataSourcesList) that is 200.
After pressing button 1, nothing happens. If I understood well, assigning a DataSource should take preference from the DataSourcesList (where there are still the three bars).
After pressing button 2, the new DatasourcesList (now with 2 series) seems to be checked fine.
Best Regards,
ImageYeray Alonso
Development & Support
Steema Software
Av. Montilivi 33, 17003 Girona, Catalonia (SP)
Image Image Image Image Image Image Please read our Bug Fixing Policy

h.hasenack
Newbie
Newbie
Posts: 32
Joined: Tue Jul 21, 2009 12:00 am
Location: Nijmegen, Netherlands

Re: Proposed patches for TCHartSeries.Datasource property

Post by h.hasenack » Tue Jul 28, 2009 7:46 am

Hi Yeray

It seems hard to find out again what exactly went wrong with the datasources. But anyway, the 'stored' predicate is still useful for the datasource property.

Check this piece of dfm,

Code: Select all

    object BarSum: TLineSeries
      Marks.Arrow.Visible = True
      Marks.Callout.Brush.Color = clBlack
      Marks.Callout.Arrow.Visible = True
      Marks.Visible = False
      DataSource = BarSeries1 
      Pointer.InflateMargins = True
      Pointer.Style = psRectangle
      Pointer.Visible = False
      XValues.Name = 'X'
      XValues.Order = loAscending
      YValues.Name = 'Y'
      YValues.Order = loNone
      DataSources = (
        'BarSeries1'
        'BarSeries2'
        'BarSeries3')
      object TeeFunction1: TAddTeeFunction
      end
    end
The line DataSource = BarSeries1 should be omitted as it conflicts with the Datasources = (...) setting. Luckily, de datasources property is stored AFTER the datasource property so no-one will notice this. But one should never rely on the order in which properties are stored.

I'm still working on reproducing the error for which the other datasources patch was required.

regards - Hans

h.hasenack
Newbie
Newbie
Posts: 32
Joined: Tue Jul 21, 2009 12:00 am
Location: Nijmegen, Netherlands

Re: Proposed patches for TCHartSeries.Datasource property

Post by h.hasenack » Tue Jul 28, 2009 8:06 am

Hi Yeray

:idea: I have managed to reproduce the trouble:

1) Run my testapp, attached to this post.
2) Click btTestSTack to add some data th the chart
3) click btTestDatasource 1, this frees BarSeries1

Hey!? My BarSum series is empty! :shock: This happens because the datasources list is cleared when 'by coincidence' the first datasource series is destroyed. This should not happen since there are 2 more datasources.

8) PS there also is a test incorporated for exporting the form to a file Formresource1.txt to demonstrate the storage of the datasource and datasources properties. (btTestDatasourceStorage)

Regards - Hans
Attachments
TestTChart.zip
Demo app demonstrating datasources trouble
(28.91 KiB) Downloaded 337 times

Yeray
Site Admin
Site Admin
Posts: 9602
Joined: Tue Dec 05, 2006 12:00 am
Location: Girona, Catalonia
Contact:

Re: Proposed patches for TCHartSeries.Datasource property

Post by Yeray » Tue Jul 28, 2009 8:41 am

Hi Hans,

I used your application to see how DataSource and DataSourcesList seem to be correctly synchronized:

1) Run my testapp, attached to this post.
2) Click btTestSTack to add some data the the chart
2.1) Click btTestDataSourceStorage to generate the corresponding txt with all the properties:

Code: Select all

//...
object BarSum: TLineSeries
  //...
  DataSource = BarSeries1
  //...
  DataSources = (
        'BarSeries1'
        'BarSeries2'
        'BarSeries3')
3) click btTestDatasource1, this frees BarSeries1
3.1) Click again btTestDataSourceStorage to generate the txt with the actual properties. As you'll see, Bar1 has been removed from the DataSourcesList and DataSource has been changed also for BarSeries2:

Code: Select all

//...
object BarSum: TLineSeries
  //...
  DataSource = BarSeries2
  //...
  DataSources = (
        'BarSeries2'
        'BarSeries3')
Then, I've added a BarSum.CheckDataSource call at btTestDatasource1 after freeing BarSeries1 and now the line doesn't disappear.

Anyway, having a DataSourcesList, probably there is no need to have a DataSource property. So I've added it to the wish list to be revised for future releases.

On the other hand, I'm still not reproducing the problem of having a series without data in the DataSourcesList.
Best Regards,
ImageYeray Alonso
Development & Support
Steema Software
Av. Montilivi 33, 17003 Girona, Catalonia (SP)
Image Image Image Image Image Image Please read our Bug Fixing Policy

h.hasenack
Newbie
Newbie
Posts: 32
Joined: Tue Jul 21, 2009 12:00 am
Location: Nijmegen, Netherlands

Re: Proposed patches for TCHartSeries.Datasource property

Post by h.hasenack » Tue Jul 28, 2009 8:46 am

Yeray,

The patch provided for TChartSeries.GetDatasource seems to be uncessesary for Tee8 as the new CalculateFunctionMany routine no longer relies on only the GetDatasource returned series to determine the # points to process. That's a lot better fix than mine... :roll:

Code: Select all

<snip>
      // Find datasource with bigger number of points... 5.02
      with ParentSeries do
      for t:=0 to DataSources.Count-1 do
      if Assigned(DataSources[t]) and
         (TChartSeries(DataSources[t]).Count>Source.Count) then
      begin
        Source:=TChartSeries(DataSources[t]);
        XList:=Source.NotMandatoryValueList;
      end;
<snip>
So the only fixes left for the datasources are:
1) The fix for the "stored" predicate of the Datasource property
2) The fix for the Notification, which I have currently boiled down to

Code: Select all

procedure TChartSeries.Notification( AComponent: TComponent;
                                     Operation: TOperation);
begin
  inherited;
  if Operation=opRemove then
{$ifdef HH_PATCH_TC_DS_NOTIFY}
  begin
{$endif}
     if AComponent=FTeeFunction then
        FTeeFunction:=nil
     else
{$ifdef HH_PATCH_TC_DS_NOTIFY}
     if (FDatasources<>nil) and (FDatasources.Indexof(aComponent)>=0) then
        InternalRemoveDataSource(AComponent);
{$else}
      { if "AComponent" is the same as series datasource,
        then set datasource to nil }
     if AComponent=DataSource then
        InternalRemoveDataSource(AComponent);  // 7.0
{$endif}
{$ifdef HH_PATCH_TC_DS_NOTIFY}
  end;
{$endif}
end;
Regards - Hans

Yeray
Site Admin
Site Admin
Posts: 9602
Joined: Tue Dec 05, 2006 12:00 am
Location: Girona, Catalonia
Contact:

Re: Proposed patches for TCHartSeries.Datasource property

Post by Yeray » Tue Jul 28, 2009 10:20 am

Hi Hans,

You patches look good. I've added them to the wish list to be revised asap (TV52014317).
Best Regards,
ImageYeray Alonso
Development & Support
Steema Software
Av. Montilivi 33, 17003 Girona, Catalonia (SP)
Image Image Image Image Image Image Please read our Bug Fixing Policy

Narcís
Site Admin
Site Admin
Posts: 14730
Joined: Mon Jun 09, 2003 4:00 am
Location: Banyoles, Catalonia
Contact:

Re: Proposed patches for TCHartSeries.Datasource property

Post by Narcís » Mon Mar 29, 2010 2:12 pm

Hi Hans,

Notice that I have implemented your enhancement suggestions to TeeChart v8 and TeeChart 2010.
Best Regards,
Narcís Calvet / Development & Support
Steema Software
Avinguda Montilivi 33, 17003 Girona, Catalonia
Tel: 34 972 218 797
http://www.steema.com
Image Image Image Image Image Image
Instructions - How to post in this forum

h.hasenack
Newbie
Newbie
Posts: 32
Joined: Tue Jul 21, 2009 12:00 am
Location: Nijmegen, Netherlands

Re: Proposed patches for TCHartSeries.Datasource property

Post by h.hasenack » Mon Mar 29, 2010 3:04 pm

Thx

Hans

Post Reply