Histogramy służą do przechowywania danych, gdzie interesuje nas liczba zliczeń w danym zakresie. ROOT obsługuje zarówno histogramy o stałej szerokości binów jak i o szerokości zmiennej. Zaczniemy w tym kursie od najprostszych histogramów czyli jednowmiarowych.

Pierwszy histogram

Do stworzenia histogramu użyjemy trzech klas. Pierwsza to TRandom która będzie generować liczby (pseudo)losowe, druga to TCanvas która reprezentuje "okno programu". Ostatnia klasa to histogram, nasz będzie jednowymiarowy i będzie przechowywał zmienne typu Double_t - czyli będzie to TH1D. Kod makra tworzącego i rysującego taki histogram wygląda następująco:

void histogram(){
    TCanvas *c1 = new TCanvas();
    TRandom *rand = new TRandom();
    TH1D *histogram = new TH1D("name","title",100,-2.0,2.0);
    for(Int_t i=0;i<1000;i++){
        histogram->Fill(rand->Gaus(0.0,1.0));
    }
    histogram->Draw();
}

Zaczynamy od utworzenia "okienka" (klasa TCanvas, zasadniczo nie jest ona potrzebna gdy rysujemy jeden histogram, gdyż w razie potrzeby potrafi on sam utworzyć sobie okienko). Następnie tworzymy klasę która generuje liczby pseudolosowe. Kolejnym krokiem jest stworzenie histogramu o 100 binach - od -2 do 2. W pętli kolejno wypełnianym histogram kolejnymi liczbami. Metodą Draw rysujemy histogram. Po uruchomieniu makra pojawi coś takiego:

 

Rys. 1. Histogram narysowany przez pierwsze makro.

Rysowanie wielu histogramów

Rysowanie wielu histogramów jest niewiele trudniejsze, wystarczy stworzyć drugi histogram, podzielić TCanvas na dwa pod-okienka (tzw. pady) w linii 10, a następnie przechodząc od padu do padu (c1->cd()) rysować kolejne histogramy:

void histogram2(){
    TCanvas *c1 = new TCanvas();
    TRandom *rand = new TRandom();
    TH1D *histogram = new TH1D("name","title",100,-2.0,2.0);
    TH1D *histogram2 = new TH1D("name","title",100,-2.0,2.0);
    for(Int_t i=0;i<1000;i++){
        histogram->Fill(rand->Gaus(0.0,1.0));
        histogram2->Fill(rand->Gaus(0.0,1.0));
    }
    c1->Divide(2,1);
    c1->cd(1);
    histogram->Draw();
    c1->cd(2);
    histogram2->Draw();
}

Rys. 2. Dwa histogramy narysowane na tym samym TCanvas ale dwóch padach.

Sprawa wygląda nieco inaczej gdy chcemy narysować dwa histogramy "na sobie". Wtedy wystarczy narysować drugi histogram z opcją "SAME". Niestety ponieważ oba histogramy są podobne, trudno będzie odróżnić jedna serię danych od drugiej, dlatego można w drugim histogramie zmienić kolor linii używanych do jego rysowania (SetLineColor):

void histogram3(){
    TCanvas *c1 = new TCanvas();
    TRandom *rand = new TRandom();
    TH1D *histogram = new TH1D("name","title",100,-2.0,2.0);
    TH1D *histogram2 = new TH1D("name","title",100,-2.0,2.0);
    for(Int_t i=0;i<1000;i++){
        histogram->Fill(rand->Gaus(0.0,1.0));
        histogram2->Fill(rand->Gaus(0.0,1.0));
    }
    histogram->Draw();
    histogram2->SetLineColor(kRed);
    histogram2->Draw("SAME");
}

Rys.3. Histogramy rysowane z opcją "SAME" i różnymi kolorami linii.

Kopiowanie histogramów najlepiej dokonywać metodą Clone, wiele ROOT'owych klasy da się kopiować w ten sposób.

TH1D *kopia = (TH1D*)original->Clone();

Histogram o zmiennej szerokości binu

Dotychczas rozważaliśmy histogramy o stałej szerokości binów, można jednak stworzyć takie o szerokości zmiennej, różnią się one jedynie konstruktorem. Poniżej makro które tworzy dwa histogramy - histogram1 o stałej szerokości binu, oraz histogram2 o zmiennej szerokości binu.

void histogram4(){
    TCanvas *c1 = new TCanvas();
    TRandom *rand = new TRandom();
    TH1D *histogram = new TH1D("name","title",10,-2.0,2.0);
    Float_t edges[11]={-2.0,-1.5,-1.0,-0.5, -0.25, 0, 0.25,0.5,1.0,1.5,2};
    TH1D *histogram2 = new TH1D("name","title",10,edges);
    for(Int_t i=0;i<1000;i++){
        histogram->Fill(rand->Gaus(0.0,1.0));
        histogram2->Fill(rand->Gaus(0.0,1.0));
    }
    histogram->Draw();
    histogram2->SetLineColor(kRed);
    histogram2->Draw("SAME");
}

 

 

W konstruktorze takiego histogramu zamiast podawać liczby binów - ich minimum i maksimum, podaję się liczbę binów a następnie tablicę o rozmiarze N+1 (gdzie N to liczba binów) która odpowiada krawędziom przedziałów. Efekt działania takiego marka zaprezentowano na rysunku 4.

Rys.4 histogram ze stałą (niebieski) oraz zmienną (czerwony) szerokością binu (czerwony).

 

Osie

Poprzednio narysowane histogramy nie posiadały nazwanych osi, co zwykle jest jednak bardzo ważne. Osie w ROOT można nazywać na dwa sposoby:

  • poprzez tytuł histogramu, zasada jest tutaj taka, że to co jest po średniku to nazwy kolejnych osi histogramów, i tak np. chcąc nazwać histogram o tytule "title", a osie "X" i "Y" powinniśmy
    • użyć konstruktora z spreparowanym tytułem np. TH1D("name","title;X;Y",100,0,1)
    • użyć metody SetTitle ze spreparowanym tytułem np. TH1D::SetTitle("title;X;Y")
  • poprzez bezpośredni dostęp do osi przykładowo
    • aby ustawić tytuł osi X TH1D::GetXaxis()->SetTitle("X");
    • aby ustawić tytuł osi Y TH1D::GetYaxis()->SetTitle("Y");

Inne opcje histogramowe

Inne często używane funkcje dla histogramów to:

  • Scale(x) która "mnoży" histogram przez x
  • Divide(TH1D*h) która dzieli histogram przez histogram h
  • GetBinContent(i) zwraca ilość wejść w i-tym binie. ROOT stosuje tutaj następującą konwencję - to co widzimy to biny od 1 do N (włącznie). Bin numer 0 to tzw. bin "underflow" to którego wrzucane są wszystkie wejścia mniejsze niż zakres histogramu, bin N+1 to bin "overflow" czyli taki który zawiera wszystkie wejścia o wartości większej niż zakres histogramu. Przykładowo jeśli popatrzymy na rysunek 4 to wartości -3 będzie w binie underflow a +4 w binie overflow.
  • GetBinError(i) zwraca niepewność statystyczną w i-tym binie
  • SetBinContent(i,x) ustawia x wejść w i-tym binie (odpowiada x-krotnemu Fill dla danego binu)
  • Sumw2() przelicza słupki błędów- szczególnie ważne w przypadku użycia SetBinContent - gdyż bez Sumw2 niepewności statystyczne są źle przeliczane
  • Reset() resetuje (zeruje) histogram

Jeśli chodzi o funkcje związane z dopasowywaniem danych oraz rysowaniem histogramów ze względu na ich ilość, będą one omówione osobno w kolejnych lekcjach. Warto tu jeszcze zwrócić uwagę że w powyższych przypadkach zawsze obok histogramu była rysowana "ramka statystyczna" można się tego pozbyć wywołując gStyle->SetOptStat(0) (wyłącza rysowanie ramki statystycznej dla każdego histogramu) lub też wyłączyć dla danego histogramu np. poprzez TH1D::SetStats(kFALSE).