Normalization with createHistogram

Hello

I’m trying to plot a RooAbsPdf with multiple observables. Since some of them are correlated, I wanted at least some bidimensional plots, using createHistogram.

What I noticed, at least in some simple cases where it can be seen, was that the plots created by createHistogram are not congruent with the ones using plotOn on a frame. Indeed, even in the 1D case, createHistogram and plotOn produce different functions.
Instead the histogram is similar to the result of plotOn with no data on the frame (which I believe is the pdf normalized only to the frame variable?).

Since I think this is a normalization issue, is there a way to properly normalize the output of createHistogram with respect to the correct observables?

Thank you in advance
Enrico

Hi @elusian,

indeed, the two commands behave differently. When you don’t do anything, all are plotting probabilities (i.e. normalised). However, if you plot data on a frame and the PDF afterwards, the PDF is normalised to the number of data events just plotted.
createHistogram() will always normalise over the observables, but you can switch that off using ConditionalObservables:
https://root.cern.ch/doc/master/classRooAbsReal.html#a6659d2c301e5cd65b83ee8c9422c2553

Sorry, I might not have explained myself properly.

Maybe an example in 1D will be better

void testPlot() {
    RooRealVar x("x", "x", -1, 1);
    RooRealVar y("y", "y", -1, 1);
    
    // basic but not too basic pdf
    // 1+r^2-3/4r^4
    RooGenericPdf pdf("pdf", "1+(x*x+y*y)-3./4*(x*x+y*y)*(x*x+y*y)", RooArgList(x,y));
    auto data = pdf.generate(RooArgSet(x, y), 100000);  // just necessary to plot the proper normalization
    
    
    auto xFrame = x.frame();
    pdf.plotOn(xFrame);
    
    auto hist = pdf.createHistogram("testHist", x, RooFit::Binning(100, -1, 1));
    
    y.setVal(1);  // setting value of y should not matter if it is actually projected in the plot
    pdf.plotOn(xFrame, RooFit::LineColor(kRed));
    
    auto hist2 = pdf.createHistogram("testHist2", x, RooFit::Binning(100, -1, 1));
    hist2->SetLineColor(kRed);
    
    // plotting data before changes the projection behaviour
    auto xFrame2 = x.frame();
    data->plotOn(xFrame2);
    // this works too if you don't want to plot the data
    // plotting data calls this method in the end
    //xFrame2->updateNormVars(RooArgSet(x, y)); 
    pdf.plotOn(xFrame2);
    
    TCanvas* c = new TCanvas;
    c->Divide(2, 2);
    c->GetPad(1)->cd();
    xFrame->Draw();
    c->GetPad(2)->cd();
    xFrame2->Draw();
    
    c->GetPad(3)->cd();
    hist2->Draw();
    hist->Draw("SAME");
    
    TLatex* l = new TLatex(0.175, 0.5, "How to get above plot with createHistogram?");
    c->GetPad(4)->cd();
    l->Draw();
}

The difference in the two RooPlots is expected and stated in the documentation: if you don’t plot data before the pdf (or manually set the frame normalization variables) the pdf will be plotted as a slice in every observable not on the frame (meaning that in the example y is sliced, hence why setting its value changes the plot).

I can reproduce the slicing behaviour with createHistogram (bottom left) but I don’t know how to project y instead, to reproduce the top right frame. This is not very useful when drawing 1D plots, but in D>1 I have no way to draw the top right plot.

ConditionalObservables does not do what I’m trying to do, I tried every combination of x and y to place inside the RooArgSet and nothing changes in the plot.

I hope this clarifies a bit what I’m asking.

Hi Enrico,

I think I understand what you need, an option to tell the function to integrate a few variables.
Normally, the argument for that would be ProjectedObservables, but the function doesn’t take that argument, yet. I can write a bit of code to see if I can add it.
There’s a possible problem, though, as both ProjectedObservables and ConditionalObservables are named the same internally. I have to check how to solve this clash.

Edit
A workaround until I’m done is likely fillHistogram. It’s used internally by createHistogram, and the set projectedVars is hardcoded to be nullptr. What I’m changing now is that you can pass IntegratedObservables(...), and that will be passed into the projectedVars such that the functions starts projecting them.

Thanks, the workaround works

I looked a bit inside fillHistogram and I think another workaround might be to call createPlotProjection before createHistogram, with the advantage that I wouldn’t need to create the histogram myself.

I’ll be happy to test the IntegratedObservables feature as soon as it is ready.

Thanks for the help
Enrico

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