Drawing with TGraph and TCanvas

Hey guys,
I’m writing my thesis at the moment and would like to draw some plots. I’m using c++11 and since I’m not a big fan of the pointer management with TCanvas, I’m trying to write a little wrapper class:

class CanvasWrapper
{
protected:
	std::shared_ptr<TCanvas> canv;
public:
	typedef std::pair<std::shared_ptr<TGraph>, std::string> Graph;
	std::vector<Graph > graphs;
	
	CanvasWrapper(const std::string& name, const std::string& title, int width, int height);
	void AddGraph(const TGraph& g, const std::string drawOptions);
	void Redraw();
	TCanvas& Canvas();
	TCanvas& operator ->();
	void SaveToFile(std::string file);
};

CanvasWrapper::CanvasWrapper(const std::string& name, const std::string& title, int width = 500, int height = 500)
{
	canv = std::make_shared<TCanvas>(name.c_str(), title.c_str(), width, height);
}
	
void CanvasWrapper::AddGraph(const TGraph& g, const std::string drawOptions)
{
	graphs.push_back(std::make_pair(std::make_shared<TGraph>(g), drawOptions));
	Redraw();
}

void CanvasWrapper::Redraw()
{
	canv->Clear();
	canv->cd();
	for(auto it = graphs.begin(); it != graphs.end(); ++it)
	{
		it->first->Draw(it->second.c_str());
	}
}

When I try to test this code with

int main(int argc, char** argv)
{
	TApplication* dummy = new TApplication("dummy", &argc, argv);
	CanvasWrapper cw("Test", "Test");
	
	unsigned int n = 3; unsigned int m = 3;
	double* x = new double[n];
	double* y = new double[n];
	for(unsigned int i = 0; i < m; i++)
	{
		for(unsigned int j = 0; j < n; j++)
		{
			x[j] = j+1;
			y[j] = pow(x[j], i);
		}
		cw.AddGraph(TGraph(n, x, y), "ALsame");
	}
	delete []x; 
	delete []y;
	dummy->Run(true);
	return 0;
}

all I see is the last graph for i = 2. I am using the option “same”, so do you know what my problem is here?
Thanks a lot,
Niklas

What are the options you pass to AddGraph? If you are repeatedly passing "A" then a new axis is drawn for every plot and the previous one will not be visible.

You could also have the canvas divided and a pad for each graph be generated:

void CanvasWrapper::Redraw()
{
	canv->Clear();
        canv->DivideSquare(graphs.size());
	for(size_t index=0;index<graphs.size();++index)
	{
                auto entry = graphs.at(index);
                canv->cd(index + 1);
		entry->first->Draw(entry->second.c_str());
	}
}

As an aside, I would recommend looking at exporting your data to something like pgfplots (TikZ). These make very nice figures and have the benefit of being tied directly to the data. The text rendering is down right in LaTeX and matches the rest of the document, the scaling of text is correct and not distorted. You can quickly go back to a plot you generated months ago and change the appearance without recalling the details of the complicated analysis that generated said figure. (Alternatively, be sure to save ROOT files with the figures so that simple changes can easily be made later.) This is a personal preference. There are some ways to do this semi automatically.

1 Like

Yes, I was passing A every time, and I changed it to only the first graph passing “A”. Now it draws 2 of the three lines, but only the first axis is drawn and this hides part of the 2nd line. So I need to check the bounds of all the TGraphs before and set them manually. Which function in TCanvas sets the bounds?
I wanted all the graphs to be in the same plot, because they represent the same data.
Can’t I save the Canvases in .root files and manually adjust them later?
Thanks a lot!

You want TAxis::SetLimits and TAxis::SetRangeUser. You cannot set the view range (RangeUser) outside the limits.

Yes you could save the canvases and adjust later.

Try a TMultiGraph.

2 Likes

The pointers to the individual graphs have to stay valid, right?

TMultiGraph::Add

1 Like

Thanks, that works very well. Last question: How do I get logarithmic axes?

After drawing something:
gPad->SetLogx(1); gPad->SetLogy(1); gPad->SetLogz(1);

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.