Getting x and y bins correspond to a maximum bin content on 2D plot

Hi root experts,

I’m trying to get x and y-axis correspond to the maximum bin content on a 2D plot. And then mark the point on the plot with the values of (x,y,z). If you look at the attached plot, you see that I get two points (x1,y1), (x2,y2) for a maximum of 9.6. So I want to get one point (x,y). I expect the maximum to be at the centre of the contour.

I need to smooth the contour in a way that gives clear contour lines. The last thing is that I don’t know why the contour lines are far away from the axes?
I attached the code I used to generate the plot. Any help is highly appreciated. Thanks.

test.C (3.1 KB)
3.root (325.6 KB)
2.root (326.0 KB)
1.root (324.6 KB)


The contours don’t start from the axes because they are drawn from the bin centres, and your histos have bin width of 10 (0 to 10, 10 to 20, etc), so their bin centres are at 5, 15, 25, etc.
As for the 2 points you are plotting, it is because in your code you are getting the lower left and upper right coordinates of the (one) bin with the maximum value; specifically, these lines are getting those 2 corners:

      double xlowbin  = total_sig->GetXaxis()->GetBinLowEdge(i);
      double xmaxbin  = total_sig->GetXaxis()->GetBinUpEdge(i);
      double ylowbin  = total_sig->GetYaxis()->GetBinLowEdge(j);
      double ymaxbin  = total_sig->GetYaxis()->GetBinUpEdge(j);

and then you are drawing them as 2 points, (30,40) and (40,50). The corresponding bin centre is actually (35,45). You can get it by using these lines instead of what you have:

  int drawxctr = 0;
  int drawyctr = 0;
  double maxSig = 0.0;
  for (int i = 1; i <= 10; i++) {
    for (int j = 1; j <= 10; j++) {
      double xmaxctr  = total_sig->GetXaxis()->GetBinCenter(i);
      double ymaxctr  = total_sig->GetYaxis()->GetBinCenter(j);
      double bin_content = total_sig->GetBinContent(i,j);
      if(total_sig->GetBinContent(i,j)==total_sig->GetMaximum()) {
        cout << " xBinCtr: " << xmaxctr;
        cout << ", yBinCtr: " << ymaxctr;
        cout << ", content: " <<bin_content<< endl;
        drawxctr = xmaxctr;
        drawyctr = ymaxctr;
        maxSig   = bin_content;
  TMarker *marker1 = new TMarker(drawxctr,drawyctr,2);
  TString maxxy =  "("+to_string(drawxctr)+","+to_string(drawyctr)+", "+to_string(maxSig)+")";
  tex = new TLatex(37,47,maxxy);


Hi Daniel,

Thanks a lot for the detailed explanation. With the lines you provided I got what I want. But still, the point is not at the centre of the last contour. Is it not expected to be right at the centre of the contour?

The contours don’t start from the axes because they are drawn from the bin centres, and your histos have bin width of 10 (0 to 10, 10 to 20, etc), so their bin centres are at 5, 15, 25, etc.

Can we do rebinning such that we get the contours to start from the axes?
I’m wondering if it’s possible to round the maxSig number so that it appears 9.6 on the plot?


Not really. All points inside a contour are represented by one value, so if you take any image of a contour you can basically choose any point inside the contour to put the label. In any case, note that here the contours are only a graphical representation but you are actually taking the maximum value (and its coordinates) from the histogram bins, so the point will be at the centre of that bin. Also in your histogram, it happens that there is only one bin with the maximum value; if there were more, you would have to choose which bin you want to use as coordinates for the label. Additionally, if you reduce the number of levels (SetNumberContours), the “maximum” contour level could contain several bins, although only one of them actually contains the maximum value…

Maybe, but let’s say the bin 0-10 has a value (signal) of 24; if you split it to 0-5, 5-10, what values would these bins take? maybe 12 and 12? you don’t have the information to split into smaller bins, so whatever you artificially chose will be biasing your results.

Instead of this line

  TString maxxy =  "("+to_string(drawxctr)+","+to_string(drawyctr)+", "+to_string(maxSig)+")";

you can do this

  Char_t maxxy[60];
  sprintf(maxxy,"%s%d%s%d%s%.1f%s","(",drawxctr,", ",drawyctr,", ",maxSig,")");

and leave the rest as it is (in %.1f you can change the 1 to the number of decimals you want to see).

I see, there’ll be no point to make the bins smaller since it may bias the result. I’m happy with the plot so thanks a lot for the help.