Undesired empty gaps when plotting TF1 functions

Hi,

I noticed that when the plotting interval is very different from the interval where a TF1 is defined, undesired white gaps (or margins) appear around the plot. The more you zoom in, the larger the gaps are. Here is a very simple macro and the corresponding plot I obtain illustrating the problem.
Of course, a question is why there are margins at all, even when the plotting range is the same as the one used for function definition.

{

	TCanvas *TestCanvas = new TCanvas("Test", "Test",600,600);
	
	// We want to plot only on a range between 0 and 2.
	TestCanvas->DrawFrame(0, 0, 2, 3);

	// A TF1 defined with a range between 0 and 2.
	// -> This one shows only small white spaces on the left and right of the curve.
	auto fa2 = new TF1("fa2","1.05 + sin(x)/x",0,2);
	fa2->SetLineColor(kGreen+3);
	fa2->Draw("SAME");

	// A TF1 defined with a range between 0 and 10.
	// -> This one shows large white spaces on the left and right of the curve.
	auto fa1 = new TF1("fa1","0.1 + sin(x)/x",0,10);
	fa1->SetLineColor(kRed);
	fa1->Draw("SAME");
	
}

My version of root is:

ROOT Version: 6.32.02
Platform: macosx64
Installed from condaforge

The problem was also there in 6.30.04, and maybe before.

It is not present in version 6.26/02 built for linuxx8664gcc.

Thanks and all the best!

Let’s ask our graphics expert @couet

See

1 Like
{
   TCanvas *TestCanvas = new TCanvas("Test", "Test",600,600);

   // We want to plot only on a range between 0 and 2.
   TestCanvas->DrawFrame(0, 0, 2, 3);

   // A TF1 defined with a range between 0 and 2.
   auto fa2 = new TF1("fa2","1.05 + sin(x)/x",0,2);
   fa2->SetLineColor(kGreen+3);
   fa2->SetNpx(500);
   fa2->Draw("SAME");

   // A TF1 defined with a range between 0 and 10.
   auto fa1 = new TF1("fa1","0.1 + sin(x)/x",0,10);
   fa1->SetLineColor(kRed);
   fa1->SetNpx(500);
   fa1->Draw("SAME");
}

Thanks for this answer!
Obviously, this solution (using SetNpx) cannot be used when the TCanvas is saved as a .C macro, since only the points are saved, and not the actual formula. That would mean functions should be created from the start with a number of points high enough. Correct?

No, it is not correct. Here is the saved canvas as a .C file. You can see SetNpx is there.

#ifdef __CLING__
#pragma cling optimize(0)
#endif
void Test()
{
//=========Macro generated from canvas: Test/Test
//=========  (Fri Oct 25 14:02:11 2024) by ROOT version 6.33.01
   TCanvas *Test = new TCanvas("Test", "Test",0,53,600,600);
   Test->Range(-0.25,-0.375,2.25,3.375);
   Test->SetFillColor(0);
   Test->SetBorderMode(0);
   Test->SetBorderSize(2);
   Test->SetFrameBorderMode(0);
   Test->SetFrameBorderMode(0);
   
   TH1F *hframe__1 = new TH1F("hframe__1","",1000,0,2);
   hframe__1->SetMinimum(0);
   hframe__1->SetMaximum(3);
   hframe__1->SetDirectory(nullptr);
   hframe__1->SetStats(0);

   Int_t ci;      // for color index setting
   TColor *color; // for color definition with alpha
   ci = TColor::GetColor("#000099");
   hframe__1->SetLineColor(ci);
   hframe__1->GetXaxis()->SetLabelFont(42);
   hframe__1->GetXaxis()->SetTitleOffset(1);
   hframe__1->GetXaxis()->SetTitleFont(42);
   hframe__1->GetYaxis()->SetLabelFont(42);
   hframe__1->GetYaxis()->SetTitleFont(42);
   hframe__1->GetZaxis()->SetLabelFont(42);
   hframe__1->GetZaxis()->SetTitleOffset(1);
   hframe__1->GetZaxis()->SetTitleFont(42);
   hframe__1->Draw(" ");
   
   TF1 *fa21 = new TF1("fa2","1.05 + sin(x)/x",0,2, TF1::EAddToList::kDefault);
   fa21->SetNpx(300);
   fa21->SetFillColor(19);
   fa21->SetFillStyle(0);

   ci = TColor::GetColor("#006600");
   fa21->SetLineColor(ci);
   fa21->SetLineWidth(2);
   fa21->GetXaxis()->SetLabelFont(42);
   fa21->GetXaxis()->SetTitleOffset(1);
   fa21->GetXaxis()->SetTitleFont(42);
   fa21->GetYaxis()->SetLabelFont(42);
   fa21->GetYaxis()->SetTitleFont(42);
   fa21->Draw("SAME");
   
   TF1 *fa12 = new TF1("fa1","0.1 + sin(x)/x",0,10, TF1::EAddToList::kDefault);
   fa12->SetNpx(500);
   fa12->SetFillColor(19);
   fa12->SetFillStyle(0);

   ci = TColor::GetColor("#ff0000");
   fa12->SetLineColor(ci);
   fa12->SetLineWidth(2);
   fa12->GetXaxis()->SetLabelFont(42);
   fa12->GetXaxis()->SetTitleOffset(1);
   fa12->GetXaxis()->SetTitleFont(42);
   fa12->GetYaxis()->SetLabelFont(42);
   fa12->GetYaxis()->SetTitleFont(42);
   fa12->Draw("SAME");
   Test->Modified();
   Test->SetSelected(Test);
}

Hi,

Gaps appears because of the way how TF1 painting is implemented.
Actually not the function, but histogram is drawn.
By default histogram contains 100 points,
but you can change number by calling fa1->SetNpx(500);.
X position of each point defined by center of each histogram bin
which is created for the range you specified for TF1.

In your case you have range 0…2, 100 points. Making position of first point 0.01.
And last point is 1.99.

If you specifies range 0…10 with 100 points, first point coordinate will be 0.05.

You can try set TF1 range slightly more than visible range,
but ROOT painting probably will not extend your drawing to frame border.

You can try web painting running your macro with root --web macro.C to check if it will work better for you.

Regards,
Sergey

In a sense it is not really satisfying to have the curve of a function not plotted over the full range on which you want the function to be plotted. But I understand it would be a big paradigm shift not to use histograms to plot functions.

Anyway, thanks a lot for all the answers!