Page 1 of 1

EMF Optimisation for charts

Posted: Wed Nov 03, 2021 12:29 pm
by 16591079
Hello.

We use Rad Studio 10.4.1 and teechart 2020.30 for c++.
We need to export charts (fastline and line series) in EMF format in reports (Fast report 6). In report we use TfrxPictureView component for chart output.

example of exporting code:

Code: Select all

const int width = static_cast<int>( pictureView->Width );
const int height = static_cast<int>( pictureView->Height );
TRect r( 0, 0, width, height * 0.95 );
auto Metafile = chart->TeeCreateMetafile( /*Enhanced*/true, r );
if ( Metafile )
{
	pictureView->Picture->Assign(Metafile);
}
it works fine, but if we have a lot of points (1000000+) report stutters, works slowly and can freeze for a few sec.

Is there any way to optimize chart before export? For example, hide unvisible points. We need emf format, not picture.

Re: EMF Optimisation for charts

Posted: Thu Nov 04, 2021 10:53 am
by yeray
Hello,

The time TeeChart spends to draw points (lines in the case of TFastLineSeries/TLineSeries) depends on factors like the number of shapes/lines to draw, the complexity of the brushes to be used (gradients, dash lines,...) and the specifications of the target machine.

We use to recommend trying to avoid drawing more points than the actual screen/app resolution, since most of them won't be shown anyway and will be wasting resources.

Please read these tips to improve the performance when drawing many points. The majority are related to the TFastLineSeries, but some of them are more general.

Re: EMF Optimisation for charts

Posted: Mon Nov 08, 2021 9:58 am
by 16591079
Thanks for the answer, We've already use almost all of tips like DrawAllPoints = false and others from reply.

Can you please give as correct link for this:
Implement as tips as possible from the ones explained in the Real-time Charting article here.
and more detailed example of TDownSampleFunction(looks like i did not install Demos)

Re: EMF Optimisation for charts

Posted: Mon Nov 08, 2021 10:21 am
by yeray
Hello,
rtech wrote:
Mon Nov 08, 2021 9:58 am
Can you please give as correct link for this:

Implement as tips as possible from the ones explained in the Real-time Charting article here.
I've just corrected the link in that post to this:
https://www.steema.com/docs/TeeChartVCLRealtime.htm
rtech wrote:
Mon Nov 08, 2021 9:58 am
and more detailed example of TDownSampleFunction(looks like i did not install Demos)
You can find the TeeNew project here, and the DownSamping example here.

Re: EMF Optimisation for charts

Posted: Mon Nov 08, 2021 12:31 pm
by 16591079
Thanks for the link.
I've tried to use TDownSampleFunction before metafile creation and i can't see any difference. Code example is here:

Code: Select all

TDownSamplingFunction *samplingFun = new TDownSamplingFunction(chart);

for(size_t i = 0; i < chart->SeriesCount(); i++)
{
	auto ser = dynamic_cast<TFastLineSeries *>(chart->Series[i]);
	if(ser)
	{
		ser->DrawStyle = flAll;
		ser->DrawAllPoints = false;
		ser->DrawAllPointsStyle = daMinMax;
		ser->AutoRepaint = false;
		ser->SetFunction(samplingFun);

		samplingFun->Tolerance = 2;
		samplingFun->DownSampleMethod = dsMinMax;
		samplingFun->Calculate(ser, 0, ser->Count() - 1);
	}
}

auto Metafile = chart->TeeCreateMetafile( /*Enhanced*/true, r );
if ( Metafile )
{
	//Подготовка графике к импорту в отчет
	pictureView->Picture->Assign(Metafile);
}
Maybe i did something wrong?

Re: EMF Optimisation for charts

Posted: Tue Nov 09, 2021 12:28 pm
by 16591079
It doesn't seem that TDownSampling function works if series have more than 15000 of points.
Adn how can i use function without second series?

Re: EMF Optimisation for charts

Posted: Tue Nov 09, 2021 12:42 pm
by yeray
Hello,

I've done a simple application to test how the export performs with the "default" TFastLineSeries, setting DrawAllPointsStyle.daMinMax, using a TDownSampleFunction and using a TDownSampleFunction with DrawAllPointsStyle.daMinMax.
MetafilePerformance.png
MetafilePerformance.png (29.28 KiB) Viewed 7842 times
As you can see, the TDownSampleFunction is a big performance improvement over the Default TFastLineSeries, but TDownSampleFunction with DrawAllPointsStyle.daMinMax isn't necessarily an improvement against the DrawAllPointsStyle.daMinMax on the Default TFastLineSeries.
MetafilePerformance.zip
(2.34 KiB) Downloaded 333 times

Re: EMF Optimisation for charts

Posted: Tue Nov 09, 2021 12:45 pm
by yeray
Hello,
rtech wrote:
Tue Nov 09, 2021 12:28 pm
It doesn't seem that TDownSampling function works if series have more than 15000 of points.
As shown in the example above, it's an improvement against using the TFastLineSeries per default. But you won't probably notice an improvement if you are using daMinMax.
rtech wrote:
Tue Nov 09, 2021 12:28 pm
Adn how can i use function without second series?
You can't, that's a requirement.

Re: EMF Optimisation for charts

Posted: Tue Nov 09, 2021 1:15 pm
by 16591079
Thanks for the example
I still can't reproduce your example. Simple code:

Code: Select all

__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
  dynamic_cast<TGDIPlusCanvas *>(Chart1->Canvas)->AntiAlias = false;
	Chart1->Axes->FastCalc = true;
	Chart1->Hover->Visible = false;

	samplingFun = new TDownSamplingFunction(this);
	Series1->DrawAllPoints = false;
  Series1->DrawAllPointsStyle = daMinMax;
	Series1->FillSampleValues(1500000);

}
//---------------------------------------------------------------------------
void __fastcall TForm1::cxButton1Click(TObject *Sender)
{
  const int width = static_cast<int>( pictureView->Width );
	const int height = static_cast<int>( pictureView->Height );
	TRect r( 0, 0, width, height * 0.95 );

	auto Metafile = Chart1->TeeCreateMetafile( /*Enhanced*/true, r );
	if(Metafile)
	{
    pictureView->Picture->Assign(Metafile);
  }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cxButton2Click(TObject *Sender)
{
	TFastLineSeries *Series2 = new TFastLineSeries(Chart1);
	samplingFun->DownSampleMethod = dsAverage;
	samplingFun->Tolerance = 2;
	Series2->SetFunction(samplingFun);
	Series2->DataSource = Series1;
  Series2->CheckDataSource();
	Chart1->AddSeries(Series2);
  Series1->Visible = false;
}
Is it correct?
As i understand, i need to create another series with datasource of first series and then use TDownSampling? But it seems like TDownSampling do nothing. Maybe i've done something wrong?
I've added sample project to this post

Re: EMF Optimisation for charts

Posted: Thu Nov 11, 2021 12:52 pm
by yeray
Hello,

I've been able to run your project after cleaning the project from packages I don't have here.
After clicking the first button, which generates the metafile below, this is what I see:
Project1_2021-11-11_13-40-53.png
Project1_2021-11-11_13-40-53.png (68.32 KiB) Viewed 7778 times

Next, I click on the second button to generate the DownSampling function, and I also click at the first button again to generate the metafile again. This is what I get:
Project1_2021-11-11_13-41-02.png
Project1_2021-11-11_13-41-02.png (70.44 KiB) Viewed 7778 times
If you debug the code, you'll see how Series1 has 1200 points (Series1->Count()), while Series2 has only 3000 (Series2->Count()) while still looking pretty similar
Of course the color is different but it's easy to correct that with:

Code: Select all

Series2->Color=Series1->Color;
So it looks correct to me.