TGraph Axis Labels Inconsistency

I see inconsistencies when the number of digits is large on the y-axis of TGraph objects (ROOT 6.11/02). I thought I had an idea about what was going on, but have just confused myself. In both C and python it seems that TGaxis::SetMaxDigits is ignored, but the results are different.

An example C script:

{
   const int numPoints = 250000;
   std::array<double, numPoints> x;
   std::array<double, numPoints> yA, yB;
   for (int i=0; i < numPoints; i++) {
      x.at(i) = i;
      yA.at(i) = gRandom->Gaus(1, 1E-4);
      yB.at(i) = gRandom->Gaus(8.23, 1E-5);
   }

   TGaxis::SetMaxDigits(1);

   TCanvas *c = new TCanvas("c","");
   c->Divide(1,2);
   c->cd(1);
   TGraph *g1 = new TGraph(numPoints, x.data(), yB.data());
   g1->Draw("ALP");
   c->cd(2);
   TGraph *g2 = new TGraph(numPoints, x.data(), yA.data());
   g2->Draw("ALP")
}

ROOT has placed all the necessary digits even though I requested max digits to be 1.


The digits are still visible here, but if I switch to one pad then they are truncated.

Finally, it we produce an equivalent python script:

import numpy as np
import ROOT

num_points = 250000
x = np.arange(num_points, dtype='float64')
y = 1E-10 * np.random.randn(num_points)
y2 = y + 8.23

ROOT.TGaxis.SetMaxDigits(1)

g = ROOT.TGraph(num_points, x, y)
g2 = ROOT.TGraph(num_points, x, y2)
c = ROOT.TCanvas("c")
c.Divide(1,2)
c.cd(1)
g.Draw("ALP")
c.cd(2)
g2.Draw("ALP")
c.Update()

raw_input("Press Enter to exit...")

I end up with the following (python 2.7) which changes behavior based on the mean:

If I switch to a single pad in python I end up with this:

My biggest concern is the last figure. If the mean value has a large number of digits then the values written along the axis may be confused for a different number as it is not always clear they are truncated leaving only the least significant digits. (This is how I ended up investigating this). I’m not sure where to go from here to make the plot readable again.

Our graphics expert, @couet will most probably take care of this…

I will check. With your macro I get (root master):

If I switch to one pad i get the 2 exact same plots.

Why in the case of the python script are you doing:

y = 1E-10 * np.random.randn(num_points)

and in the case of C++:

      yB.at(i) = gRandom->Gaus(8.23, 1E-5);

??

If you use power -10 or -5 for both you will get similar plots in C++ and python.

I think in this particular case the Y axis cannot have its number of digits changed as the difference between labels is at the 5th or 10th decimal … if you reduce the number of digits you will end up with several time the same label.

You are correct, that was an oversight of mine.

How do we deal with this then? Allow the scaling factor on the top to become 8 x 10^-10, then the lower numbers could be represented with fewer digits?

Lets take the two first labels. They are:

8.22998
8.22996

this is equivalent to:

8.2299 + 0.00008
8.2299 + 0.00006

so you can represent them as:

    10^-5 + 8.2299
    +---
    |
8   +-
    | 
6   +-
    |

The tricky part is the offset ‘8.2299’ … ROOT does not provides the offset. Only the multiplication factor.

I see this as a useful extension. Beats being confused about why you thought the values should be around 8 and instead you see 2998 or 22998.

What do you mean ? the labels are around 8 … only they need 5 digits to be diffirent …

Depending on the size of the gutter along the y-xais the labels are sometimes cutoff and you see the incorrect values:

  +------------(PAD)------
  |
8.|22998 +----(GRAPH)-----
  |      |
8.|22996 +- 
  |      |

This is what led me to this post. I knew the values should be at 8, but I was getting labels at ~22990, becasue I could not see the “8.”. Your suggestion above would have resolved my issue as I would have:

  +----------(PAD)------
  |    10^-5 + 8.2299
  |    +----(GRAPH)-----
  |    |
  | 8  +-
  |    | 
  | 6  +-
  |    |

Oh I see … because of the clipping on the Pad … I understand now . Yes the only way right now is to increase the left margin or reduce the label size.

And you only do this if you know the values are being truncated, which I contend is not always the case. (I spent some time trying to figure out where I had mistakenly changed the values in the code, and in the end found them to be exactly what I thought. Not the best way to do be spending time doing analysis.) An analysis tool is only good if it can be trusted.

I do not disagree with you, I just say that this offset at the top of the axis is not implement.
Right now I have no idea how difficult/easy it is to implement…

Time for a JIRA ticket?

I guess so … a new feature not a bug report …

Agreed. The other option is to shrink the frame of the graph until the labels fit.

Yes … this can be also an other solution …

I think I do want the offset label mechanism. I just wanted to provide the alternative I had thought of. Automatically, shrinking the graph has drawbacks as well, for a large number of digits the plot becomes tiny and the label is mostly repeating which doesn’t provide much value.

(Sorry I was too fast and didn’t see you edit. I’ll leave this here as it clarifies the alternative.)

JIRA ticket: Loading...

1 Like

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