Scope of TChart.Assign method

TeeChart VCL for Borland/CodeGear/Embarcadero RAD Studio, Delphi and C++ Builder.
Post Reply
Toreba
Newbie
Newbie
Posts: 29
Joined: Wed Sep 02, 2015 12:00 am

Scope of TChart.Assign method

Post by Toreba » Tue Apr 05, 2016 9:57 am

Hi,

The TChart.Assign method seems not to copy series attributes, such as colour and title. To copy series attributes, I have to use separate TChartSeries.Assign calls.

But I don't have to do this with TChartAxis. The TChart.Assign method copies axis attributes but not series attributes.

Is this the expected behaviour?

Thanks

Toreba

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

Re: Scope of TChart.Assign method

Post by Yeray » Wed Apr 06, 2016 9:28 am

Hello Toreba,

Note the assign methods assign the values of the properties form the source to the target. Since the series are objects that at the same time store a reference to their parent chart, changing that would remove the series from the original chart.
I'd suggest you to use the CloneChart series after assigning or cloning the chart. Ie:

Code: Select all

CloneChartSeries(Series1, Chart2);
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

Toreba
Newbie
Newbie
Posts: 29
Joined: Wed Sep 02, 2015 12:00 am

Re: Scope of TChart.Assign method

Post by Toreba » Fri Apr 08, 2016 4:23 pm

Yeray,

Ah yes, I see what you mean.

In fact, what I'm trying to do is allow a user to reset all display attributes of a chart by picking a template, i.e. a saved graph with no data, previously streamed to a database BLOB field using SaveChartToStream. But once the saved chart is retrieved, there doesn't seem to be a combination of available methods that allows me to code a function that updates display attributes from the saved graph, while leaving the chart series values untouched. In the end I have to rebuild all the series value lists from their data sources, which is a lot slower than merely updating their display attributes.

Or am I missing something that would help?

Regards

Toreba

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

Re: Scope of TChart.Assign method

Post by Yeray » Mon Apr 11, 2016 8:14 am

Hello Toreba,

I've done a simple example doing what I understand you are trying to achieve.
- Chart1 has some settings modified (I apply a theme to it). It also has a series with some values.
- Chart2 has another series with other data loaded.
- Button1 exports Chart1 to a memory stream (without the data), loads the chart to a tmpChart and then applies the formatting to Chart2. So Chart2 now looks as Chart1, using a stream and without moving any series or data.

Code: Select all

uses Series, TeeThemes, TeeStore;

procedure TForm1.FormCreate(Sender: TObject);
begin
  with Chart1.AddSeries(TBarSeries) as TBarSeries do
  begin
    ColorEachPoint:=true;
    FillSampleValues();
  end;

  ApplyChartTheme(TAndrosTheme, Chart1);

  with Chart2.AddSeries(TPieSeries) as TPieSeries do
  begin
    FillSampleValues();
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var tmpStream: TMemoryStream;
    tmpChart: TChart;
begin
  //save to stream
  tmpStream:=TMemoryStream.Create;
  SaveChartToStream(Chart1, tmpStream, false);

  //load from stream
  tmpStream.Position:=0;
  tmpChart:=TChart.Create(Self);
  LoadChartFromStream(tmpChart, tmpStream);

  Chart2.Assign(tmpChart);

  tmpStream.Free;
  tmpChart.Free;
end;
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

Toreba
Newbie
Newbie
Posts: 29
Joined: Wed Sep 02, 2015 12:00 am

Re: Scope of TChart.Assign method

Post by Toreba » Mon Apr 11, 2016 5:26 pm

Yeray,

That's not quite what I'm trying to do. The saved chart stores properties of the TChart and properties of each of its TChartSeries. I want to recover these series properties as well as the chart properties.

If I slightly modify your code as below, then clicking the button updates Chart2 with the View3D property of Chart1, and sure, it leaves the data on Chart2 untouched, but it doesn't update the series ColorEachPoint property on Chart2.

Using the TChartSeries.Assign method won't work because it will delete all the existing data points. Are there any other methods I might use, without having to shunt the data into a temporary array? I wasn't really aware of chart themes. Would that mechanism achieve what I want to do?

Code: Select all

with Chart1.AddSeries(TBarSeries) as TBarSeries do
  begin
    ColorEachPoint:=true;
    FillSampleValues();
  end;

  Chart1.View3D := False;

  with Chart2.AddSeries(TBarSeries) as TBarSeries do
  begin
    ColorEachPoint:=false;
    FillSampleValues();
  end;

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

Re: Scope of TChart.Assign method

Post by Yeray » Tue Apr 12, 2016 10:44 am

Hello,

You can use AssignFormat to copy the properties from a series to another without copying the data.
Just add this at the Button1Click method, after assigning the chart properties:

Code: Select all

  Chart2[0].AssignFormat(tmpChart[0]);
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

Toreba
Newbie
Newbie
Posts: 29
Joined: Wed Sep 02, 2015 12:00 am

Re: Scope of TChart.Assign method

Post by Toreba » Wed Apr 27, 2016 2:17 pm

Yeray,

Thanks for the advice. The AssignFormat works very well in all respects except one. If the series uses the default colour assigned automatically at series creation, that colour is not streamed to the saved chart. It then appears that when using the AssignFormat method, the colour of the target series is not updated as the property is not specified in the saved version. So I need to force the default series colour to be streamed. Is that possible?

If not I guess I have to abandon the default colouring and always set the series to some other colour that isn't the default.

In addition, how can I tell at run-time whether a series has it's default colour?

Regards

Toreba

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

Re: Scope of TChart.Assign method

Post by Yeray » Fri Apr 29, 2016 2:36 pm

Hello Toreba,

In this case, you actually want to copy a property TChart property from a chart to the other: the ColorPalette array. Note this array is used to color the points/series when you haven't explicitly assigned a color the points/series.
This ColorPalette array is exported to the stream, but if you don't assign the TChart, the default palette is used in the destination chart.
So you can assign the ColorPalette with this:

Code: Select all

  Chart2.ColorPalette:=tmpChart.ColorPalette;
On the other hand, if the source series has the Colors explicitly assigned, then you'll have to manually copy them. The array of colors in a series isn't copied in the AssignFormat method because they are in close relation with the values; there's a color per each x and y value.
However, you can still copy the colors if you want. Here is how you can do it:

Code: Select all

  TChartSeriesAccess = class(TChartSeries)
//...
uses Series, TeeThemes, TeeStore;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  ApplyChartTheme(TAndrosTheme, Chart1);

  with Chart1.AddSeries(TBarSeries) as TBarSeries do
  begin
    ColorEachPoint:=true;
    FillSampleValues();

    //test with colors assigned
    {for i:=0 to Count-1 do
      ValueColor[i]:=AndroidPalette[i];}
  end;

  Chart1.View3D := False;

  with Chart2.AddSeries(TBarSeries) as TBarSeries do
  begin
    ColorEachPoint:=false;
    FillSampleValues();
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);

  Procedure AssignColors(Source: TChartSeries; Dest: TChartSeries);
  var t : Integer;
  begin
    if Assigned(TChartSeriesAccess(Source).FColors) then
    begin
      if Assigned(TChartSeriesAccess(Dest).FColors) then
        TChartSeriesAccess(Dest).FColors.Clear
      else
        TChartSeriesAccess(Dest).FColors:=TList{$IFDEF D18}<TColor>{$ENDIF}.Create;

      for t:=0 to TChartSeriesAccess(Source).FColors.Count-1 do
        TChartSeriesAccess(Dest).FColors.Add(TChartSeriesAccess(Source).FColors[t]);
    end
    else
      FreeAndNil(TChartSeriesAccess(Dest).FColors);
  end;

var tmpStream: TMemoryStream;
    tmpChart: TChart;
    i: Integer;
begin
  //save to stream
  tmpStream:=TMemoryStream.Create;
  SaveChartToStream(Chart1, tmpStream, true);

  //load from stream
  tmpStream.Position:=0;
  tmpChart:=TChart.Create(Self);
  LoadChartFromStream(tmpChart, tmpStream);

  Chart2[0].AssignFormat(tmpChart[0]);

  Chart2.ColorPalette:=tmpChart.ColorPalette;

  AssignColors(tmpChart[0], Chart2[0]);

  tmpStream.Free;
  tmpChart.Free;
end;
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

Toreba
Newbie
Newbie
Posts: 29
Joined: Wed Sep 02, 2015 12:00 am

Re: Scope of TChart.Assign method

Post by Toreba » Wed May 04, 2016 11:26 am

Hi Yeray,

Thanks for the advice.

Actually, I am using the chart Assign method, so I think the ColorPalette is being copied successfully. But that's not the solution either. In a typical use case, the user does this:
- He creates a chart and accepts all the default colours. He maybe sets some text captions, but otherwise is happy with the default set-up;
- He saves the chart to stream (to database);
- Next session he reloads the chart from stream (from database) and all is well;
- He re-orders the series for clarity, but makes no other changes;
- He saves the chart to stream again. So, still. the saved version contains no explicit colours for series, and the colour palette is unchanged;
. Next session he reloads the chart, and finds that re-ordered series pick up the wrong default colour from the default color palette.

So if I understand you correctly, at some point in the history of the excellent TChart, it has been decided that it's better to treat the series color property as a default property, whose value comes from the color palette, rather than as a non-defaulted property which is easier for the coder to test and manipulate. Fair enough. But as I see it, my best way round this might be to introduce my own CustomColor property which I can save to and retrieve from the stream, and set that to record the actual series colour. Does that sound sensible to you?

Regards

Toreba

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

Re: Scope of TChart.Assign method

Post by Yeray » Wed May 04, 2016 3:29 pm

Hello Toreba,

Could you please arrange a simple example project we can run as-is to reproduce the problem here?
Thanks in advance.
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

Post Reply