Page 1 of 1
Proposed patches for TCHartSeries.Datasource property
Posted: Fri Jul 24, 2009 11:49 am
by 10553957
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
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
when series are destroyed. Only the Datasource property is checked in the original code, and the datasources list is forgotten
.
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
Re: Proposed patches for TCHartSeries.Datasource property
Posted: Mon Jul 27, 2009 3:13 pm
by yeray
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.
Re: Proposed patches for TCHartSeries.Datasource property
Posted: Tue Jul 28, 2009 7:46 am
by 10553957
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
Re: Proposed patches for TCHartSeries.Datasource property
Posted: Tue Jul 28, 2009 8:06 am
by 10553957
Hi Yeray
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!
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.
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
Re: Proposed patches for TCHartSeries.Datasource property
Posted: Tue Jul 28, 2009 8:41 am
by yeray
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.
Re: Proposed patches for TCHartSeries.Datasource property
Posted: Tue Jul 28, 2009 8:46 am
by 10553957
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...
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
Re: Proposed patches for TCHartSeries.Datasource property
Posted: Tue Jul 28, 2009 10:20 am
by yeray
Hi Hans,
You patches look good. I've added them to the wish list to be revised asap (TV52014317).
Re: Proposed patches for TCHartSeries.Datasource property
Posted: Mon Mar 29, 2010 2:12 pm
by narcis
Hi Hans,
Notice that I have implemented your enhancement suggestions to TeeChart v8 and TeeChart 2010.
Re: Proposed patches for TCHartSeries.Datasource property
Posted: Mon Mar 29, 2010 3:04 pm
by 10553957
Thx
Hans