Manipulating histogram that has drawn the axis

Hi all,

I have several functions that do return a pointer to the histogram that draw the axis in the current canvas, in order to modify the axis properties.

What I want to do works successfully when I return THStack::GetHistogram() or TGraph::GetHistogram() but not in the example below:

#include "TH1.h"
#include "TCanvas.h"
#include "TROOT.h"
#include "TStyle.h"

#include <vector>

bool HistScaledGT ( TH1* h1, TH1* h2 )
{ 
	return (h1->GetMaximum()/h1->Integral()) < (h2->GetMaximum()/h2->Integral());
}

template <class T>
T* DrawNormHists( const std::vector<T*> &h_vec )
{
	
	typename std::vector<T*>::const_iterator it, it2;
	
	it = max_element( h_vec.begin(), h_vec.end(), HistScaledGT );
	
	if( it != h_vec.end() )
	{ 
		(*it)->DrawNormalized("hist"); // Drawn with axis
		for( it2 = h_vec.begin() ; it2 != h_vec.end() ; it2++ )
			if( (*it2)->Integral() > 0 ) (*it2)->DrawNormalized("hist same A");
	}
	
	return *it; // Return histogram used to build axis
	
}


int main()
{
	gROOT->SetStyle("Plain");
	// gStyle->SetOptTitle(0);
	gStyle->SetOptStat(0);
	
	std::vector<TH1F*> h_vec;
	
	h_vec.push_back( new TH1F("h1", "h1", 50, -10, 10) );
	h_vec.back()->FillRandom("gaus");
	h_vec.push_back( new TH1F("h2", "h2", 50, -10, 10) );
	h_vec.back()->FillRandom("landau");
	h_vec.push_back( new TH1F("h3", "h3", 50, -10, 10) );
	h_vec.back()->FillRandom("expo"); // This will be the maximum
	h_vec.back()->SetTitle("InitTitle");
	
	TCanvas *c = new TCanvas("tmp","", 600, 600);
	
	TH1* f = DrawNormHists( h_vec );
	
	// These don't work. Why ?
	f->SetTitle("A title");
	f->GetXaxis()->SetTitle("Hello");

	c->Modified();
	c->Update();
	c->ForceUpdate(); // Even after this
	
	c->Print(".png");
	
	return 0;

}

What am I doing wrong ?

Is there another option to draw a bunch of normalized histograms so that they plot nicely. I could fill a THStack with scaled histograms but I’d rather avoid duplicating the histograms.

Is there any reason why THStack has no DrawNormalized() member function?

I am using ROOT 5.18/00 trunk@21744 on MacOS X. Is it time to upgrade ?

Thanks in advance for your help.

Karolos

Your macro gives me errors. Can you send something I can run in ROOT ?
In principal what you are doing is correct. Though you do not need the option “A” when you plot histogram using the option “SAME”… But should not make any difference.

Hi Olivier,

Thanks for your reply.

I removed the template and renamed the main().

The attached code runs fine on my version of ROOT 5.18/00 trunk@21744 on MacOS X.

root -l tmp_root.C

It produces the results but it doesn’t allow me to change the title (or the axis title, which is my main need) of the histogram that draw the axes.

Indeed, the A is a leftover from iterations in the code but it doesn’t hurt.

Karolos
tmp_root.C (1.4 KB)

Hi Karolos,

Still something wrong with your macro:

pb-d-128-141-132-114:roottest couet$ root -l tmp_root.C
root [0] 
Processing tmp_root.C...
Error: Function comp(*result,*first) is not defined in current scope  algo.h:2341:
*** Interpreter error recovered ***
root [1] 

Olivier,

I’m sorry. I checked this code on several machines including LXPLUS and it worked fine.

In any case, I did remove the call to the STL max_element, which is not the purpose of my post.

I again checked on the platforms I have available. I hope it works for you too now.

Thanks,

Karolos
tmp_root2.C (1.64 KB)

It is ok now. I can run your macro. I’ll let you know.

Great. Thank you.

I do not understand yet. The only way I found to make it work right now is to set the h3’s attributes before calling DrawNormHists. Is that acceptable for you ?

The following very stupid one is working:

TH1F* DrawHists(TH1F *h1, TH1F *h2, TH1F *h3)
{
   TH1F *h = h3;
   h3->Draw();
   h2->Draw("same");
   h1->Draw("same");
   return h;
}


tmp_root3()
{
   TH1F *h1 = new TH1F("h1", "h1", 50, -10, 10);
   h1->FillRandom("gaus");

   TH1F *h2 = new TH1F("h2", "h2", 50, -10, 10);
   h2->FillRandom("landau");

   TH1F *h3 = new TH1F("h3", "h3", 50, -10, 10);
   h3->FillRandom("expo");
   

   TCanvas *c = new TCanvas("tmp","", 600, 600);

   TH1F* f = DrawHists( h1, h2, h3 );
   f->SetTitle("A title");
   f->GetXaxis()->SetTitle("Hello");
}

Thank you Olivier.

To search for the histogram that is going to be plotted defeats the purpose of a single function returning the histogram that is of importance. Applying the axis title to all the histograms beforehand is also not optimal. But I can live with that.

The strange thing is that this example works if TH1s had been TGraphs inside a TMultiGraph, for which I return TMultiGraph::GetHistogram(). Perhaps this is a hint to the solution ?

BTW is there any reason why there’s no THStack::DrawNormalized() ? Since THStack::GetHistogram() works just fine too.

In any case, it’s not really a critical issue. It would just be nice that things work as expected (unless I’m doing something weird).

Thanks,

Karolos

I suspect that some how the wrong histogram is returned in you case as it works correctly in the last example I sent you … But I must Admit I have not found what is wrong in your macro.

Indeed, my code works fine when using TH1::Draw().

Now that I think of it, normalized drawing should derive a new histogram not to erase the old. So I need to get the pointer to the DrawNormalized() histogram.

Thanks Olivier for investigating this.

Solution yielded using

TH1F *retval;
retval = (TH1F*) (*it)->DrawNormalized("hist"); // Drawn with axis

return retval;

in appropriate places.

Karolos

[quote=“couet”]The following very stupid one is working:

[code]
TH1F* DrawHists(TH1F *h1, TH1F *h2, TH1F *h3)
{
TH1F *h = h3;
h3->Draw();
h2->Draw(“same”);
h1->Draw(“same”);
return h;
}

tmp_root3()
{
TH1F *h1 = new TH1F(“h1”, “h1”, 50, -10, 10);
h1->FillRandom(“gaus”);

TH1F *h2 = new TH1F(“h2”, “h2”, 50, -10, 10);
h2->FillRandom(“landau”);

TH1F *h3 = new TH1F(“h3”, “h3”, 50, -10, 10);
h3->FillRandom(“expo”);

TCanvas *c = new TCanvas(“tmp”,"", 600, 600);

TH1F* f = DrawHists( h1, h2, h3 );
f->SetTitle(“A title”);
f->GetXaxis()->SetTitle(“Hello”);
}
[/code][/quote]

Yes, I think that’s the way you should investigate.